实现八大行星绕太阳3D旋转效果,这波操作不来喊个666?-程序员宅基地

640?wx_fmt=jpeg


/   今日科技快讯   /


针对媒体报道的关于法拉第未来进行重组以及贾跃亭或辞去CEO职务的内容,FF发布声明称,已正式进入公司顶层治理架构变革的执行阶段,近期会公布相关细节。对于贾跃亭的债务问题,FF声明称,贾跃亭过去两年来通过多种方式已陆续偿还超过30亿美金的国内债务,还债信托基金的设立就是为了尽快彻底解决债务问题。


/   作者简介   /


明天又是愉快的周末了,提前祝大家周末愉快!


本篇文章来自史蒂芬诺夫斯基的投稿,分享了自己的自定义View,相信会对大家有所帮助!同时也感谢作者贡献的精彩文章。


史蒂芬诺夫斯基的博客地址:

https://www.jianshu.com/u/46056ddc3d3d


/   本文目的   /


  • 巩固/练习 自定义View

  • 分析解决问题的思路


好久没写View了,最近恰巧遇到一个八大行星绕太阳旋转的假3D效果,写完之后感觉效果还不错。能玩十分钟的那种。


本篇将一步步带您实现这样的一个效果,ps:我是用kotlin实现的,介于您可能还不太熟悉kotlin或者不像熟悉java那样,所以本篇使用java语言(写的过程中老是忘记写new和分号报错)。


先上最终效果图(录制的比较渣)


640?wx_fmt=gif


需要解决的问题


1. 行星的整体布局,3D的视觉效果

2. 行星转到太阳后面时,会被太阳挡住,转到太阳前面时,会挡住太阳

3. 行星自动旋转,并且可以根据手势滑动,滑动完之后继续自动旋转

4. 中间的太阳有照射的旋转动画


/   分析问题   /


1. 行星的整体布局,3D的视觉效果


如果我们draw()的之前通过Camera将Canvas绕x轴旋转60°是不是就可以搞定?这种方式实则是不可行的。因为draw()之前Canvas的变化会作用于子View,从效果图可以看出,子View并没有rotateX的变换,只有缩放变换。所以我们通过子View layout时变化其位置,即计算子View的left、top、right、bottom四个值


行星绕太阳旋转其轨迹实际上就是圆形,如下图:


640?wx_fmt=png


我们看手机,其实是沿着z轴方向。想象一下,如果让坐标系沿着x轴旋转60°,不就能达到我们想要的效果了嘛。


旋转60°,我们再沿着x轴方向看,如下图:


640?wx_fmt=png


图中蓝色是旋转前的轨迹,紫色是旋转之后的轨迹。假设P点是地球,P旋转前的y坐标是y0,则旋转之后地球的y坐标是:


y0 * 旋转角度的余切值,即:


y1 = y0* cos(60°)


好了。现在的结论是,只需要把图1的所有行星的y 坐标 * cos60°,就能达到效果了。


而图1中,计算各个行星旋转之前的x 、y坐标比较简单。


x0 = Radius * cos60°

y0 = Radius * sin60°


2. 行星转到太阳后面时,会被太阳挡住,转到太阳前面时,会挡住太阳


640?wx_fmt=png


刚看到这个效果,觉得这个问题是个比较难的点,如果所有行星的父容器和太阳是平级关系,结果就是要么所有的行星都会挡住太阳,要么就是太阳都会挡住行星。不能达到行星转到太阳后面时,会被太阳挡住,转到太阳前面时,会挡住太阳 * 的这种效果


但是如果所有的行星和太阳是平级关系,即他们是同一个父容器下的子View,那么我们就可以达到这个效果,方法有三种:


1、重写父容器dispatchDraw()方法,改变子View的绘制顺序(图3中先draw土星,再draw太阳,再draw地球);


2、在子View draw之前依次调用bringToFront()方法(图3中先调用土星的bringToFront()方法,再调用太阳的bringToFront()方法,最后调用地球的bringToFront()方法);


3、通过改变所有子View的z值(高度)以改变View的绘制顺序。


这三种方法理论是都可以实现,但是方法1 成本太高、风险也高,重新dispatchDraw()可能会发生未知问题。


至于方法2,细心的朋友可能发现,每次调用bringToFront()方法,都会出发requestLayout(),降低了测量布局绘制效率,更重要的原因是在layout(问题1的解决需要重新layout方法)之后再调用requestLayout()方法,会导致循环layout-draw-layout-draw-layout-draw....


综上,我们选择方法3。简单,风险小。


3. 行星自动旋转,并且可以根据手势滑动,滑动完之后继续自动旋转


  • 自动滑动:在父容器中设置一个成员变量:角度偏移量sweepAngle,计算子View的位置时将偏移量也考虑进去。然后定时不断增加或者减小sweepAngle(增加或减小 将决定子View是顺时针or逆时针旋转)

  • 手势:用的比较多,从后面的代码中体现。


4. 中间的太阳有照射的旋转动画


效果图中的太阳由两张图片组成,一张是前景,一张是背景带亮光,让背景图绕着z轴无限旋转即可。


/   开始编码   /


核心就是行星的父容器



/**
 * 行星和太阳的父容器
 *
 * @author guolong
 * @since 2019/8/20
 */

public class StarGroupView extends FrameLayout {

    // 从这个角度开始画View ,可以调整
    private static final float START_ANGLE = 270f// 270°
    // 父容器的边界 单位dp
    private static final int PADDING = 80;
    // 绕x轴旋转的角度 70°对应的弧度
    private static final double ROTATE_X = Math.PI * 7 / 18;
    // 以上几个值都可以根据最终效果调整

    /**
     * 角度偏差值
     */

    private float sweepAngle = 0f;

    /**
     * 行星轨迹的半径
     */

    private float mRadius;

    /**
     * 父容器的边界 ,单位px
     */

    private int mPadding;

    public StarGroupView(@NonNull Context context) {
        this(context, null);
    }

    public StarGroupView(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public StarGroupView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // 边距转换为px
        mPadding = (int) (context.getResources().getDisplayMetrics().density * PADDING);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
//        super.onLayout(changed, left, top, right, bottom);
        mRadius = (getMeasuredWidth() / 2f - mPadding);
        layoutChildren();
    }

    private void layoutChildren() {
        int childCount = getChildCount();
        if (childCount == 0return;
        // 行星之间的角度
        float averageAngle = 360f / childCount;
        for (int index = 0; index < childCount; index++) {
            View child = getChildAt(index);
            int childWidth = child.getMeasuredWidth();
            int childHeight = child.getMeasuredHeight();

            // 第index 个子View的角度
            double angle = (START_ANGLE - averageAngle * index + sweepAngle) * Math.PI / 180;
            double sin = Math.sin(angle);
            double cos = Math.cos(angle);

            double coordinateX = getMeasuredWidth() / 2f - mRadius * cos;
            // * Math.cos(ROTATE_X) 代表将y坐标转换为旋转之后的y坐标
            double coordinateY = mRadius / 2f - mRadius * sin * Math.cos(ROTATE_X);

            child.layout((int) (coordinateX - childWidth / 2),
                    (int) (coordinateY - childHeight / 2),
                    (int) (coordinateX + childWidth / 2),
                    (int) (coordinateY + childHeight / 2));

            // 假设view的最小缩放是原来的0.3倍,则缩放比例和角度的关系是
            float scale = (float) ((1 - 0.3f) / 2 * (1 - Math.sin(angle)) + 0.3f);
            child.setScaleX(scale);
            child.setScaleY(scale);
        }
    }
}


然后再xml中配置View



<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".LandActivity">

    <com.glong.demo.view.StarGroupView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/tv1"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:background="@color/colorAccent"
            android:gravity="center"
            android:text="1" />

        <TextView
            android:id="@+id/tv2"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:background="@android:color/darker_gray"
            android:gravity="center"
            android:text="2" />

        <TextView
            android:id="@+id/tv3"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:background="@android:color/holo_green_dark"
            android:gravity="center"
            android:text="3" />

        <TextView
            android:id="@+id/tv4"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:background="@android:color/holo_blue_dark"
            android:gravity="center"
            android:text="4" />

        <TextView
            android:id="@+id/tv5"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:background="@android:color/holo_green_light"
            android:gravity="center"
            android:text="5" />

        <TextView
            android:id="@+id/tv6"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:background="@android:color/holo_orange_light"
            android:gravity="center"
            android:text="6" />

        <TextView
            android:id="@+id/tv7"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:background="#ff3311"
            android:gravity="center"
            android:text="7" />

        <TextView
            android:id="@+id/tv8"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:background="#11aa44"
            android:gravity="center"
            android:text="8" />

        <TextView
            android:id="@+id/tv9"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:background="#ff99cc"
            android:gravity="center"
            android:text="9" />

    </com.glong.demo.view.StarGroupView>

</androidx.constraintlayout.widget.ConstraintLayout>


运行,效果如下:


640?wx_fmt=png


上述代码正如前面分析的,计算所有子View的left 、top 、right 、bottom,注释写的也详细。说明两点:


1、其中,64行


double angle = (START_ANGLE - averageAngle * index + sweepAngle) * Math.PI / 180;


公式中- averageAngle * index代表逆时针添加,如果是+ averageAngle * index则是顺时针添加。


2、78到80行,计算子View的scale,这里说明下角度和scale的计算公司


float scale = (float) ((1 - 0.3f) / 2 * (1 - Math.sin(angle)) + 0.3f);


假如View的最小scale是0.3f,最大scale是1。按照效果View在270°时scale最大,在90°时scale最小,并且从270°到90°scale越来越小。正玄曲线如下:


640?wx_fmt=png


正玄曲线中,270°最小,90°时最大,我们把正玄值取反然后再加1,那么[90°,270°]对应的值就是[0,1]


即,设 z = -sin(angle) + 1 当angle在90°到270°变化时 ,z将在0到1之间变化


z在0~1之间变化时,scale 要在0.3~1之间变化,如下图:


640?wx_fmt=png


显然


scale = (1 - 0.3) * z + 0.3 = (1-0.3)*(-sin(angle) + 1)+0.3


接下来,再把中间的太阳加进去


太阳也是StarGroupView的子View,但是和其他子View 不同的是,太阳在最中间,不参与类似行星的位置计算


简单期间我们使用tag=“center"来标识子View是中间的太阳。


修改xml文件



    <com.glong.demo.view.StarGroupView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <!-- 增加太阳View -->
        <ImageView
            android:layout_width="130dp"
            android:layout_height="130dp"
            android:src="@drawable/ic_launcher_background"
            android:tag="center" />

        <!--省略行星-->
    </com.glong.demo.view.StarGroupView>


修改 StarGroupView.java



public class StarGroupView extends FrameLayout {
  // ... 省略部分代码

      private void layoutChildren() {
        int childCount = getChildCount();
        if (childCount == 0return;
        // 行星之间的角度
        View centerView = centerView();
        float averageAngle;
        if (centerView == null) {
            averageAngle = 360f / childCount;
        } else {
            // centerView 不参与计算角度
            averageAngle = 360f / (childCount - 1);
        }

        int number = 0;
        for (int index = 0; index < childCount; index++) {
            View child = getChildAt(index);
            int childWidth = child.getMeasuredWidth();
            int childHeight = child.getMeasuredHeight();

            // 如果是centerView 直接居中布局
            if ("center".equals(child.getTag())) {
                child.layout(getMeasuredWidth() / 2 - childWidth / 2, getMeasuredHeight() / 2 - childHeight / 2,
                        getMeasuredWidth() / 2 + childWidth / 2, getMeasuredHeight() / 2 + childHeight / 2);
            } else {
                // 第index 个子View的角度
                double angle = (START_ANGLE - averageAngle * number + sweepAngle) * Math.PI / 180;
                double sin = Math.sin(angle);
                double cos = Math.cos(angle);

                double coordinateX = getMeasuredWidth() / 2f - mRadius * cos;
                // * Math.cos(ROTATE_X) 代表将y坐标转换为旋转之后的y坐标
                double coordinateY = mRadius / 2f - mRadius * sin * Math.cos(ROTATE_X);

                child.layout((int) (coordinateX - childWidth / 2),
                        (int) (coordinateY - childHeight / 2),
                        (int) (coordinateX + childWidth / 2),
                        (int) (coordinateY + childHeight / 2));

                // 假设view的最小缩放是原来的0.3倍,则缩放比例和角度的关系是
                float scale = (float) ((1 - 0.3f) / 2 * (1 - Math.sin(angle)) + 0.3f);
                child.setScaleX(scale);
                child.setScaleY(scale);
                number++;
            }
        }
    }

    /**
     * 获取centerView
     *
     * @return 太阳
     */

    private View centerView() {
        View result = null;
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            if ("center".equals(child.getTag())) {
                return child;
            }
        }
        return null;
    }
}


代码注释写的很全面,不做过多解释了,这个时候我们把PADDING改大一点,改成160,运行如下:


640?wx_fmt=png


问题很明显,3应该在4的上面, 2 应该在3的上面,中间的View应该在5,6的上面。


这是因为系统默认按照View的添加顺序画View的,即我们xml文件里面的顺序。xml里面我们centerView在第一个,所以就先画centerView,导致centerView被其他View覆盖。按照上面的分析,动态改变View的z值以改变View的draw顺序。


修改StarGroupView.java代码



public class StarGroupView extends FrameLayout {

    private void layoutChildren() {
        // ...省略之前代码
        changeZ();
    }

    /**
     * 改变子View的z值以改变子View的绘制优先级,z越大优先级越低(最后绘制)
     */

    private void changeZ() {
        View centerView = centerView();
        float centerViewScaleY = 1f;
        if (centerView != null) {
            centerViewScaleY = centerView.getScaleY();
            centerView.setScaleY(0.5f);
        }
        List<View> children = new ArrayList<>();
        for (int i = 0; i < getChildCount(); i++) {
            children.add(getChildAt(i));
        }
        // 按照scaleY排序
        Collections.sort(children, new Comparator<View>() {
            @Override
            public int compare(View o1, View o2) {
                return (int) ((o1.getScaleY() - o2.getScaleY())*1000000);
            }
        });
        float z = 0.1f;
        for (int i = 0; i < children.size(); i++) {
            children.get(i).setZ(z);
            z += 0.1f;
        }
        if (centerView != null) {
            centerView.setScaleY(centerViewScaleY);
        }
    }
}


我们先给所有子View根据他的scaleY排序,由于centerView的scaleY 在layoutChildren()时并没有改变,我们把centerView的scaleY设置为0.5f,最后再还原回去。现在运行,效果如下:


640?wx_fmt=png


到这里基本已经达到了我们想要的效果啦,接下来让其自动旋转和响应手势,肯定就难不倒我们啦。


加入自动旋转


子StarGroupView中循环postDelayed(runnable,16)即可,这里为什么是16ms,大家都懂


修改StarGroupView.java



public class StarGroupView extends FrameLayout {
    // ...省略已有代码

    //自动旋转角度,16ms(一帧)旋转的角度,值越大转的越快
    private static final float AUTO_SWEEP_ANGLE = 0.1f;

    private Runnable autoScrollRunnable = new Runnable() {
        @Override
        public void run() {
            sweepAngle += AUTO_SWEEP_ANGLE;
            // 取个模 防止sweepAngle爆表
            sweepAngle %= 360;
            Log.d("guolong""auto , sweepAngle == " +sweepAngle);
            layoutChildren();
            postDelayed(this16);
        }
    };

    public StarGroupView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // ...省略已有代码
        postDelayed(autoScrollRunnable,100);
    }
}


这样就开始自动旋转了,调节AUTO_SWEEP_ANGLE的值 改变旋转速度


加入手势


老写法,先上代码


在StarGroupView.java中增加



public class StarGroupView extends FrameLayout {

    //px转化为angle的比例  ps:一定要给设置一个转换,不然旋转的太欢了
    private static final float SCALE_PX_ANGLE = 0.2f;


    /**
     * 手势处理
     */

    private float downX = 0f;
    /**
     * 手指按下时的角度
     */

    private float downAngle = sweepAngle;
    /**
     * 速度追踪器
     */

    private VelocityTracker velocity = VelocityTracker.obtain();
    /**
     * 滑动结束后的动画
     */

    private ValueAnimator velocityAnim = new ValueAnimator();

    public StarGroupView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        // ...
        initAnim();
    }

    private void initAnim() {
        velocityAnim.setDuration(1000);
        velocityAnim.setInterpolator(new DecelerateInterpolator());
        velocityAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float value = (float) animation.getAnimatedValue();
                // 乘以SCALE_PX_ANGLE是因为如果不乘 转得太欢了
                sweepAngle += (value * SCALE_PX_ANGLE);
                layoutChildren();
            }
        });
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        velocity.addMovement(event);
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downX = x;
                downAngle = sweepAngle;

                // 取消动画和自动旋转
                velocityAnim.cancel();
                removeCallbacks(autoScrollRunnable);
                return true;
            case MotionEvent.ACTION_MOVE:
                float dx = downX - x ;
                sweepAngle = (dx * SCALE_PX_ANGLE + downAngle);
                layoutChildren();
                break;
            case MotionEvent.ACTION_UP:
                velocity.computeCurrentVelocity(16);
                // 速度为负值代表顺时针
                scrollByVelocity(velocity.getXVelocity());
                postDelayed(autoScrollRunnable, 16);
        }
        return super.onTouchEvent(event);
    }

    private void scrollByVelocity(float velocity) {
        float end;
        if (velocity < 0)
            end = -AUTO_SWEEP_ANGLE;
        else
            end = 0f;
        velocityAnim.setFloatValues(-velocity, end);
        velocityAnim.start();
    }
}


手势处理的代码比较简单,这里就不再赘述了,需要注意的是


1. ACTION_DOWN需返回true,不然收不到后续的ACTION_MOVE事件;

2. ACTION_DOWN时需要暂停动画和自动旋转

3. 这里根据手指离开屏幕时的速度做Animator动画,当然你也可以用scroller实现。

4. 第59行,我们给dx * SCALE_PX_ANGLE代表一个像素可以转换成SCALE_PX_ANGLE角度


最后,加上中间太阳旋转的动画


在res/anim/sun_anim.xml



<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="true"
    android:interpolator="@android:interpolator/linear">
    <rotate
        android:duration="8000"
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:repeatCount="-1"
        android:toDegrees="360" />
</set>


在Activity中



public class LandActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // ....省略部分代码

        View sunView = findViewById(R.id.sun_view);
        sunView.startAnimation((AnimationUtils.loadAnimation(this, R.anim.sun_anim)));
    }
}


最后的最后,我们可以给外部提供start和pause方法用来暂停和开始动画



public class StarGroupView extends FrameLayout {

    // 省略...
    public void pause() {
        velocityAnim.cancel();
        removeCallbacks(autoScrollRunnable);
    }

    public void start() {
        postDelayed(autoScrollRunnable, 16);
    }
}


最终算上注释不到260代码搞定!最终效果:


640?wx_fmt=gif


完整的Demo代码和星球效果代码放在github上了


https://github.com/GarrettLance/Demos


推荐阅读:

腾讯新开源的插件化框架 Shadow,原来是这么玩的

总是听到有人说AndroidX,到底什么是AndroidX?

给你的Android应用穿件花衣服吧!


欢迎关注我的公众号

学习技术或投稿


640.png?


640?wx_fmt=jpeg

长按上图,识别图中二维码即可关注


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/c10WTiybQ1Ye3/article/details/100164332

智能推荐

oracle 12c 集群安装后的检查_12c查看crs状态-程序员宅基地

文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态

解决jupyter notebook无法找到虚拟环境的问题_jupyter没有pytorch环境-程序员宅基地

文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境

国内安装scoop的保姆教程_scoop-cn-程序员宅基地

文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn

Element ui colorpicker在Vue中的使用_vue el-color-picker-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker

迅为iTOP-4412精英版之烧写内核移植后的镜像_exynos 4412 刷机-程序员宅基地

文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机

Linux系统配置jdk_linux配置jdk-程序员宅基地

文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk

随便推点

matlab(4):特殊符号的输入_matlab微米怎么输入-程序员宅基地

文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入

C语言程序设计-文件(打开与关闭、顺序、二进制读写)-程序员宅基地

文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。‍ Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。

Touchdesigner自学笔记之三_touchdesigner怎么让一个模型跟着鼠标移动-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动

【附源码】基于java的校园停车场管理系统的设计与实现61m0e9计算机毕设SSM_基于java技术的停车场管理系统实现与设计-程序员宅基地

文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计

Android系统播放器MediaPlayer源码分析_android多媒体播放源码分析 时序图-程序员宅基地

文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;amp;gt;Jni-&amp;amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图

java 数据结构与算法 ——快速排序法-程序员宅基地

文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法