直播点赞动画实现

一、效果及原理

先放一张效果图:

从效果图中可以看出,点赞飘心的效果是动画组合而成的,遇到一个复杂的动画效果,首先我们考虑应该是能不能用现有的Api效果拆分实现,如果不行再考虑完全自定义的实现,毕竟写算法很烦。言归正传,上图的这个效果,仔细观察可以将其拆分为俩部分动画,一个是心出现由小到大的动画,一个是往上飘的动画。已拆分发现已有的api完全没问题那么接下来看具体实现。

二、代码实现
(一)为了方便调用将效果写在一个自定义布局中,首先是图片的初始化
 private void init() {
        interpolators = new Interpolator[4];
        interpolators[0] =line;
        interpolators[1] =acc;
        interpolators[2] =dce;
        interpolators[3] =accdec;

        //准备图片集合
        drawables[0] = getResources().getDrawable(R.mipmap.red);
        drawables[1] = getResources().getDrawable(R.mipmap.yellow);
        drawables[2] = getResources().getDrawable(R.mipmap.blue);

        //得到图片的原始高度
        dWidth = drawables[0].getIntrinsicWidth();
        dHeight = drawables[0].getIntrinsicHeight();
        params = new LayoutParams(dWidth, dHeight);
        //将iv添加到父容器底部、水平居中位置
        params.addRule(CENTER_HORIZONTAL);
        params.addRule(ALIGN_PARENT_BOTTOM);

    }
(二)初始化完成后需要的就是给图片添加动画了
1、给图片添加俩动画,刚开始的心出现动画,接着的心上漂动画,然后组合之后按照先后顺序执行,
 // 得到一个iv的动画集合
    private AnimatorSet getAnimator(ImageView iv){
        //平移、透明度渐变、缩放动画
        //1.alpha动画
        ObjectAnimator alpha = ObjectAnimator.ofFloat(iv, "alpha", 0.3f, 1f);
        //2.缩放动画
        ObjectAnimator scaleX = ObjectAnimator.ofFloat(iv, "scaleX", 0.3f, 1f);
        ObjectAnimator scaleY = ObjectAnimator.ofFloat(iv, "scaleY", 0.3f, 1f);
        //三个动画同时执行
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.setDuration(600);
        animatorSet.playTogether(alpha,scaleX,scaleY);

        //设置平移的曲线动画---贝塞尔曲线
        ValueAnimator bezierAnimator = getBezierValueAnimator(iv);

        AnimatorSet set = new AnimatorSet();
        //按序列执行
        set.playSequentially(animatorSet,bezierAnimator);
        set.setTarget(iv);
        return set;
    }
其中上移动画采用的是4阶贝塞尔曲线,自定义了一个估值器,套了下公式,代码如下:
public class BezierEvaluator implements TypeEvaluator<PointF> {

    private PointF pointF1;
    private PointF pointF2;

    public BezierEvaluator(PointF pointF1, PointF pointF2) {
        this.pointF1 = pointF1;
        this.pointF2 = pointF2;
    }

    @Override
    public PointF evaluate(float t, PointF pointF0, PointF pointF3) {
        //t百分比:0~1
        // b(t)=p0*(1-t)*(1-t)*(1-t)+3*p1*t*(1-t)*(1-t)+3*p2*t*t*(1-t)+p3*t*t*t
        PointF pointF = new PointF();
        pointF.x = pointF0.x * (1 - t) * (1 - t) * (1 - t) + 3 * pointF1.x * t * (1 - t) * (1 - t) +
                3 * pointF2.x * t * t * (1 - t)
                + pointF3.x * t * t * t;
        pointF.y = pointF0.y  * (1 - t) * (1 - t) * (1 - t) + 3 * pointF1.y  * t * (1 - t) * (1 - t) +
                3 * pointF2.y  * t * t * (1 - t)
                + pointF3.y  * t * t * t;

        return pointF;
    }
}
调用估值器完成上漂动画的细节如下:
 //得到一个贝塞尔曲线动画
    private ValueAnimator getBezierValueAnimator(final ImageView iv) {
        //根据贝塞尔公式确定四个点(起始点p0,拐点1p1,拐点2p2,终点p3)
        PointF pointF0 = new PointF((mWidth - dWidth) / 2, mHeight - dHeight);
        PointF pointF3 = new PointF(random.nextInt(mWidth), 0);
        PointF pointF1 = getPointF(1);
        PointF pointF2 = getPointF(2);
        //估值器Evaluator,来控制view的行驶路径(不断地修改point.x,point.y)
        BezierEvaluator bezierEvaluator = new BezierEvaluator(pointF1, pointF2);
        //属性动画不仅仅可以改变view的属性,还可以改变自定义的属性(比如Point)
        ValueAnimator valueAnimator = ValueAnimator.ofObject(bezierEvaluator, pointF0, pointF3);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                PointF pointF = (PointF) animation.getAnimatedValue();
                iv.setX(pointF.x);
                iv.setY(pointF.y);
                iv.setAlpha(1-animation.getAnimatedFraction());
            }
        });
        valueAnimator.setDuration(4000);
        return valueAnimator;
    }
2、向外暴露一个方法,能够调用动画的方法

public void addIcon(){
        //添加心形,并开始执行动画
        final ImageView iv = new ImageView(getContext());
        iv.setImageDrawable(drawables[random.nextInt(3)]);
        //将iv添加到父容器底部、水平居中位置
        iv.setLayoutParams(params);
        addView(iv);
        //开始属性动画:平移、透明度渐变、缩放动画
        AnimatorSet set = getAnimator(iv);

        //监听动画执行完毕,将iv移除或者复用
        set.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                removeView(iv);
            }
        });
        //开启动画
        set.start();
    }

3、在activity中调用下此方法就好了
mBt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mLoveLayout.addIcon();
            }
        });

三、代码链接
代码已经上传至github,链接为: LoveLayout



  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值