美文网首页
贝塞尔曲线动画效果

贝塞尔曲线动画效果

作者: fengfancky | 来源:发表于2019-12-18 16:00 被阅读0次

    效果

    bs_anim.gif

    贝塞尔曲线

    贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。它是依据四个位置任意的点(三阶)坐标绘制出的一条光滑曲线。
    三次方公式:

    bs_formula.png

    P0、P1、P2、P3四个点在平面或在三维空间中定义了三次方贝兹曲线。

    使用ValueAnimator实现贝塞尔曲线动画

    根据需求确定4个位置

        //随机创建4个点
        int startX = 0;
        int startY = 0;
    
        int midX = dp2px(this,new Random().nextInt(100)-50);
        int midY = dp2px(this,new Random().nextInt(300));
    
        int midX1 = dp2px(this,new Random().nextInt(500)-50);
        int midY1 = dp2px(this,new Random().nextInt(500));
    
        int endX = dp2px(this,new Random().nextInt(500)-50) ;
        int endY = dp2px(this,650);
    

    获取ValueAnimator对象
    根据贝塞尔曲线的参数方程,得知参数t的取值范围为 0~1。

    ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,1f);
    

    实现AnimatorUpdateListener

     valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float t = (float) animation.getAnimatedValue();//此为函数自变量t的值 0~1
    
                //根据公式计算出视图当前位置
                float bsX = (float) (xP[0]*Math.pow(1-t,3)+3*xP[1]*t*Math.pow(1-t,2)+3*xP[2]*Math.pow(t,2)*(1-t)+xP[3]*Math.pow(t,3));
                float bsY = (float) (yP[0]*Math.pow(1-t,3)+3*yP[1]*t*Math.pow(1-t,2)+3*yP[2]*Math.pow(t,2)*(1-t)+yP[3]*Math.pow(t,3));
    
                //设置视图当前状态,偏移量和大小
                view.setTranslationX(bsX);
                view.setTranslationY(-bsY);
                view.setScaleX(t*1.5f);
                view.setScaleY(t*1.5f);
    
                //运动到末端时淡出
                if (t>0.8){
                    view.setAlpha(5-t*5);
                }
            }
        });
    

    完整代码

    public class BsAnimActivity extends Activity {
    
        private ImageView imageView;
        private FrameLayout addLl;
        Timer timer;
        TimerTask timerTask;
        private static final int ADD_ANIM_VIEW= 1001;
        private static final int PERIOD_TIME= 800; //间隔时间
        private static final int ANIM_TOTAL_TIME= 10000; //动画时长
    
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.bs_layout);
            imageView = findViewById(R.id.bsAnim);
            addLl = findViewById(R.id.add_ll);
    
            cycImgAnim(imageView);
            initAnim();
        }
    
        private void cycImgAnim(View v){
            ObjectAnimator objectAnimatorX = ObjectAnimator.ofFloat(v,"scaleX",1.4f);
            ObjectAnimator objectAnimatorY = ObjectAnimator.ofFloat(v,"scaleY",1.4f);
            objectAnimatorX.setRepeatMode(ValueAnimator.REVERSE);
            objectAnimatorX.setRepeatCount(ValueAnimator.INFINITE);//无限次
            objectAnimatorY.setRepeatMode(ValueAnimator.REVERSE);
            objectAnimatorY.setRepeatCount(ValueAnimator.INFINITE);
            AnimatorSet animatorSet = new AnimatorSet();
            animatorSet.playTogether(objectAnimatorX,objectAnimatorY);
            animatorSet.setDuration(800);
            animatorSet.start();
        }
       
        private void initAnim(){
            timer = new Timer();
            timerTask = new TimerTask() {
                @Override
                public void run() {
                    handler.sendEmptyMessage(ADD_ANIM_VIEW);
                }
            };
            timer.schedule(timerTask,0,PERIOD_TIME);
        }
    
        Handler handler = new Handler(new Handler.Callback() {
            @Override
            public boolean handleMessage(@NonNull Message message) {
                if (message.what == ADD_ANIM_VIEW){
                    bsAnim();
                }
                return false;
            }
        });
    
        //创建视图,添加到容器,使视图按三次贝塞尔曲线运动
        private void bsAnim(){
            FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(50,50);
            layoutParams.gravity = Gravity.LEFT | Gravity.BOTTOM;
            layoutParams.setMargins(dp2px(this,30),0,0,dp2px(this,100));
            ImageView imageView = new ImageView(this);
            imageView.setLayoutParams(layoutParams);
            imageView.setFocusable(false);
            imageView.setImageDrawable(getResources().getDrawable(R.drawable.heart_f));
            addLl.addView(imageView);
            updateAnim(imageView);
        }
    
    
        //三次贝塞尔曲线动画
        private void updateAnim(final View view){
    
            //根据需求随机创建4个点
            int startX = 0;
            int startY = 0;
    
            int midX = dp2px(this,new Random().nextInt(100)-50);
            int midY = dp2px(this,new Random().nextInt(300));
    
            int midX1 = dp2px(this,new Random().nextInt(500)-50);
            int midY1 = dp2px(this,new Random().nextInt(500));
    
            int endX = dp2px(this,new Random().nextInt(500)-50) ;
            int endY = dp2px(this,650);
    
            final float[] xP = new float[]{startX,midX,midX1,endX};
            final float[] yP = new float[]{startY,midY,midY1,endY};
    
            ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,1f);
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float t = (float) animation.getAnimatedValue();
    
                    //根据公式计算出视图当前位置
                    float bsX = (float) (xP[0]*Math.pow(1-t,3)+3*xP[1]*t*Math.pow(1-t,2)+3*xP[2]*Math.pow(t,2)*(1-t)+xP[3]*Math.pow(t,3));
                    float bsY = (float) (yP[0]*Math.pow(1-t,3)+3*yP[1]*t*Math.pow(1-t,2)+3*yP[2]*Math.pow(t,2)*(1-t)+yP[3]*Math.pow(t,3));
    
                    //设置视图当前状态,偏移量和大小
                    view.setTranslationX(bsX);
                    view.setTranslationY(-bsY);
                    view.setScaleX(t*1.5f);
                    view.setScaleY(t*1.5f);
    
                    //运动到末端时淡出
                    if (t>0.8){
                        view.setAlpha(5-t*5);
                    }
                }
            });
    
            valueAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    addLl.removeView(view);//动画结束移除视图
                }
            });
            valueAnimator.setDuration(ANIM_TOTAL_TIME);//时长
            valueAnimator.start();
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            if (timer!=null){
                timer.cancel();
                timer = null;
            }
            if (timerTask!=null){
                timer.cancel();
                timerTask = null;
            }
        }
    
        public static int dp2px(Context context, float dpVal) {
            return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                dpVal, context.getResources().getDisplayMetrics());
        }
    
    }
    

    布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/add_ll"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <ImageView
            android:id="@+id/bsAnim"
            android:focusable="false"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_gravity="left|bottom"
            android:layout_marginLeft="30dp"
            android:layout_marginBottom="100dp"
            android:src="@drawable/heart_f"/>
    </FrameLayout>
    

    相关文章

      网友评论

          本文标题:贝塞尔曲线动画效果

          本文链接:https://www.haomeiwen.com/subject/ggpwgctx.html