美文网首页待写
4.Android 抖音点赞动效完美实现 200行

4.Android 抖音点赞动效完美实现 200行

作者: 鹏城十八少 | 来源:发表于2021-06-18 22:57 被阅读0次

    请问:简书怎么可以把代码格式调整?我贴出来换格式了。你们直接去Github下载工程!

    效果分析:

    可以基本分为两个部分,具体看实现

    1.点击START ANIM按钮的时候,底部出现一个ImageView它的drawable是随机的,并伴着缩放和透明度的变化;

    2.等第一步的动画执行完后开始向上移动,移动的轨迹是一个曲线,我们要用到贝塞尔曲线公式去不断的改变图片的位置。

    效果实现:

    1.自定义控件Releativielayout,绘制出爱心控件

    2.移动是一个曲线:配合估值器+贝塞尔曲线

    3.自定义估值器封装:贝塞尔估值器

    4.贝塞尔曲线实现:三阶贝塞尔:4个点确定,有一个公式

    p1和P2的确定点公式

    p0 :起点可以确定

    p1:比p0的y值大

    p2 要比p1的y值大

    p3:终点可以确定

    整个曲线我们可以简单的理解为这个S路曲线,S也会有四个点:

    1.P0最下面的这个起点,也就是我们刚刚添加进来最下方居中的这个点 ((mWidth - mDrawableWidth) / 2, mHeight- mDrawableHeight)

    2.P1是下半部分抛物线的顶点,这里是随机;

    3.P2是上半部分抛物线的顶点,这里也是随机;

    4.P3是最上面位置的终点(mRandom.nextInt(mWidth), 0),也就是最上面的这个点;

    5.t的范围是[0,1],我们确定这四个点之后就开始套公式了:

    5.view通过改变x和y的值。x和y就是一个点,通过动画得到(估值器得到)。点通过贝塞尔曲线

    图片设置x,y,alpha。

    因为估值器里面的定义是一个点。

    @Override

    public PointFevaluate(float t, PointF p0, PointF p3) {

    PointF pointF=new PointF();

        pointF.x=p0.x*(1-t)*(1-t)*(1-t)

    +3*p1.x*t*(1-t)*(1-t)

    +3*p2.x*t*(t)*(1-t)

    +p3.x*t*t*t;

        pointF.y=p0.y*(1-t)*(1-t)*(1-t)

    +3*p1.y*t*(1-t)*(1-t)

    +3*p2.y*t*(t)*(1-t)

    +p3.y*t*t*t;

        return pointF;

    PointF pointF=(PointF) valueAnimator.getAnimatedValue();//这个返回值就是估值器的值

    ValueAnimator  objectAnimator = ObjectAnimator.ofObject(new LoveTypeEvalutor(point1, point2), point0, point3);

    objectAnimator.setDuration(2000);

    objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

    @Override

        public void onAnimationUpdate(ValueAnimator valueAnimator) {

    Log.d("dddd","onAnimationUpdate");

            PointF pointF=(PointF) valueAnimator.getAnimatedValue();//这个返回值就是估值器的值

            float r=valueAnimator.getAnimatedFraction();//这个值

            imageView.setX(pointF.x);//setx:指的是谁

            imageView.setY(pointF.y);

            imageView.setAlpha(1-r+0.2f);

        }

    });

    先说一下这种效果都用到了哪些东西:

    1.自定义View的一些基础;

    2.随机数的使用;

    3.插补器的使用;

    4.属性动画的一些高级用法

    5.贝塞尔曲线应用到属性动画

    public class DouyinPraiseextends RelativeLayout {

    Randomrandom;

        public DouyinPraise(Context context) {

    this(context, null);

        }

    public DouyinPraise(Context context, AttributeSet attrs) {

    this(context, attrs, 0);

            random =new Random();

        }

    public DouyinPraise(Context context, AttributeSet attrs, int defStyleAttr) {

    super(context, attrs, defStyleAttr);

        }

    private int width;

        private int height;

        private int imageWidth, imageHeight;

        @Override

        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

            width = MeasureSpec.getSize(widthMeasureSpec);

            height = MeasureSpec.getSize(heightMeasureSpec);

        }

    public void addImageView() {

    RelativeLayout.LayoutParams layoutParams =new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);

            layoutParams.addRule(ALIGN_PARENT_BOTTOM);

            layoutParams.addRule(CENTER_HORIZONTAL);

            ImageView imageView =new ImageView(getContext());//如何得到view,inlat。可以直接new

            imageView.setImageResource(R.mipmap.ic_launcher);//如何获取图片的宽高

            imageWidth = imageView.getWidth();

            imageHeight = imageView.getHeight();

            addView(imageView, layoutParams);

            AnimatorSet animatorSet = getObjectAnimator(imageView);

            animatorSet.start();

        }

    private AnimatorSetgetObjectAnimator(ImageView view) {

    AnimatorSet animatorSetAll =new AnimatorSet();

            AnimatorSet animatorSet =new AnimatorSet();

            ObjectAnimator objectAnimatorAlpha = ObjectAnimator.ofFloat(view, "alpha", 0.3f, 1.0f);

            ObjectAnimator objectAnimatorScalex = ObjectAnimator.ofFloat(view, "scaleX", 0.1f, 1.0f);

            ObjectAnimator objectAnimatorScaleY = ObjectAnimator.ofFloat(view, "scaleY", 0.1f, 1.0f);

            animatorSet.playTogether(objectAnimatorAlpha, objectAnimatorScalex, objectAnimatorScaleY);

            animatorSet.setDuration(500);

            animatorSetAll.playSequentially(animatorSet, getBziAnimation(view));//播放动画

            animatorSetAll.start();

            return animatorSet;

        }

    /***

        * 三次方公式

        * @return

        */

        private AnimatorgetBziAnimation(ImageView imageView) {

    PointF point0 =new PointF(width /2, height);

            PointF point1 =new PointF(new Random().nextInt(width), random.nextInt(height/2));

            PointF point2 =new PointF(new Random().nextInt(width), random.nextInt(height/2)+height/2);

            PointF point3 =new PointF(new Random().nextInt(width), 0);

            ValueAnimator  objectAnimator = ObjectAnimator.ofObject(new LoveTypeEvalutor(point1, point2), point0, point3);

            objectAnimator.setDuration(2000);

            objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

    @Override

                public void onAnimationUpdate(ValueAnimator valueAnimator) {

    Log.d("dddd","onAnimationUpdate");

                    PointF pointF=(PointF) valueAnimator.getAnimatedValue();//这个返回值就是估值器的值

                    float r=valueAnimator.getAnimatedFraction();//这个值

                    imageView.setX(pointF.x);//setx:指的是谁

                    imageView.setY(pointF.y);

                    imageView.setAlpha(1-r+0.2f);

                }

    });

            objectAnimator.addListener(new Animator.AnimatorListener() {

    @Override

                public void onAnimationStart(Animator animator) {

    }

    @Override

                public void onAnimationEnd(Animator animator) {

    removeView(imageView);

                }

    @Override

                public void onAnimationCancel(Animator animator) {

    }

    @Override

                public void onAnimationRepeat(Animator animator) {

    }

    });

            return objectAnimator;

        }

    public class LoveTypeEvalutorimplements TypeEvaluator {

    private PointFp1,p2;

        public LoveTypeEvalutor(PointF p1, PointF p2) {

    this.p1 = p1;

            this.p2 = p2;

        }

    @Override

        public PointFevaluate(float t, PointF p0, PointF p3) {

    PointF pointF=new PointF();

            pointF.x=p0.x*(1-t)*(1-t)*(1-t)

    +3*p1.x*t*(1-t)*(1-t)

    +3*p2.x*t*(t)*(1-t)

    +p3.x*t*t*t;

            pointF.y=p0.y*(1-t)*(1-t)*(1-t)

    +3*p1.y*t*(1-t)*(1-t)

    +3*p2.y*t*(t)*(1-t)

    +p3.y*t*t*t;

            return pointF;

        }

    }

    https://blog.csdn.net/qq_16624353/article/details/93376688

    https://www.jianshu.com/p/2a830d089310

    demo地址:https://github.com/pengcaihua123456/shennandadao

    相关文章

      网友评论

        本文标题:4.Android 抖音点赞动效完美实现 200行

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