一步一步实现Periscope点赞效果

1. 效果


这里写图片描述

说一下这种效果都用到了哪些东西:
1.自定义View的一些基础;
2.随机数的使用;
3.插补器的使用;
4.属性动画的一些高级用法
5.贝塞尔曲线应用到属性动画

2.分析和实现


2.1效果实现:

  可以基本分为两个部分,具体看实现
  1.点击START ANIM按钮的时候,底部出现一个ImageView它的drawable是随机的,并伴着缩放和透明度的变化;
  2.等第一步的动画执行完后开始向上移动,移动的轨迹是一个曲线,我们要用到贝塞尔曲线公式去不断的改变图片的位置。
  

2.2分步实现: 

  1.自定义View继承RelativeLayout,初始化一些基本的参数:

public class LoveLayout extends RelativeLayout {
    private Drawable mRed, mYellow, mBlue;
    private Drawable[] mDrawables;
    private Interpolator[] mInterpolators;
    private int mDrawableHeight, mDrawableWidth;
    private int mWidth, mHeight;
    private LayoutParams params;
    private Random mRandom = new Random();

    public LoveLayout(Context context) {
        this(context, null);
    }

    public LoveLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public LoveLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        initDrawable();
        initInterpolator();
        // 初始化params
        params = new LayoutParams(mDrawableWidth, mDrawableHeight);
        // 父容器水平居中
        params.addRule(CENTER_HORIZONTAL, TRUE);
        // 父容器的底部
        params.addRule(ALIGN_PARENT_BOTTOM, TRUE);
    }

    /**
     * 初始化几种插补器
     */
    private void initInterpolator() {
        mInterpolators = new Interpolator[4];
        mInterpolators[0] = new LinearInterpolator();// 线性
        mInterpolators[1] = new AccelerateDecelerateInterpolator();// 先加速后减速
        mInterpolators[2] = new AccelerateInterpolator();// 加速
        mInterpolators[3] = new DecelerateInterpolator();// 减速
    }

    private void initDrawable() {
        mRed = getResources().getDrawable(R.drawable.pl_red);
        mYellow = getResources().getDrawable(R.drawable.pl_yellow);
        mBlue = getResources().getDrawable(R.drawable.pl_blue);

        mDrawables = new Drawable[3];
        mDrawables[0] = mRed;
        mDrawables[1] = mYellow;
        mDrawables[2] = mBlue;

        // 得到图片的实际宽高
        mDrawableWidth = mRed.getIntrinsicWidth();
        mDrawableHeight = mRed.getIntrinsicHeight();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mWidth = getMeasuredWidth();
        mHeight = getMeasuredHeight();
    }
}

  2.当点击START NIMA的时候不断的往容器里面添加随机的ImageView,然后开始执行透明度的缩放的动画,这里用属性动画ObjectAnimator.ofFloat();

    /**
    * 添加点赞图片
    **/
    public void addLove() {
        final ImageView loveIv = new ImageView(getContext());
        loveIv.setImageDrawable(mDrawables[mRandom.nextInt(mDrawables.length)]);
        loveIv.setLayoutParams(params);
        addView(loveIv);

        // 最终的属性动画集合
        AnimatorSet finalSet = getAnimatorSet(loveIv);
        finalSet.start();
    }

    /**
     * 构造三个属性动画
     */
    private AnimatorSet getAnimatorSet(ImageView loveIv) {
        // 1.alpha动画
        ObjectAnimator alpha = ObjectAnimator
                .ofFloat(loveIv, "alpha", 0.3f, 1f);

        // 2.缩放动画
        ObjectAnimator scaleX = ObjectAnimator.ofFloat(loveIv, "scaleX", 0.2f,
                1f);
        ObjectAnimator scaleY = ObjectAnimator.ofFloat(loveIv, "scaleY", 0.2f,
                1f);
        // 刚刚进入动画集合
        AnimatorSet enter = new AnimatorSet();
        enter.setDuration(500);
        enter.playTogether(alpha, scaleX, scaleY);
        enter.setTarget(loveIv);
        return enter;
    }

  这里我们可以试着看看效果,是不是可以伴随着动画添加到容器底部了。

  3.利用三次方贝塞尔曲线,来不断的修改ImageView的位置,这里我们要看看这个方程,我们要继承这个估值器TypeEvaluator,至于贝塞尔是大学高数中的东西了,可以简单分析一下:
  
  这里写图片描述

整个曲线我们可以简单的理解为这个S路曲线,S也会有四个点:
1.P0最下面的这个起点,也就是我们刚刚添加进来最下方居中的这个点 ((mWidth - mDrawableWidth) / 2, mHeight- mDrawableHeight)
2.P1是下半部分抛物线的顶点,这里是随机;
3.P2是上半部分抛物线的顶点,这里也是随机;
4.P3是最上面位置的终点(mRandom.nextInt(mWidth), 0),也就是最上面的这个点;
5.t的范围是[0,1],我们确定这四个点之后就开始套公式了:

// 贝塞尔估值器
public class BezierEvaluator implements TypeEvaluator<PointF> {
    private PointF point1, point2;

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

    @Override
    public PointF evaluate(float t, PointF point0, PointF point3) {
        // t百分比, 0~1
        PointF point = new PointF();
        point.x = point0.x * (1 - t) * (1 - t) * (1 - t) //
                + 3 * point1.x * t * (1 - t) * (1 - t)//
                + 3 * point2.x * t * t * (1 - t)//
                + point3.x * t * t * t;//

        point.y = point0.y * (1 - t) * (1 - t) * (1 - t) //
                + 3 * point1.y * t * (1 - t) * (1 - t)//
                + 3 * point2.y * t * t * (1 - t)//
                + point3.y * t * t * t;//
        // 套用上面的公式把点返回
        return point;
    }

}

  4.利用属性动画这个方法ValueAnimator.ofObject(),然后添加监听不断的改变ImageView的x,y坐标值,当然还有一些后续工作如动画执行完后将ImageView移除释放资源等等。

    /**
     * 贝塞尔曲线动画(核心,不断的修改ImageView的坐标ponintF(x,y) )
     */
    private ValueAnimator getBezierValueAnimator(final ImageView loveIv) {
        // 曲线的两个顶点
        PointF pointF2 = getPonitF(2);
        PointF pointF1 = getPonitF(1);
        // 起点位置
        PointF pointF0 = new PointF((mWidth - mDrawableWidth) / 2, mHeight
                - mDrawableHeight);
        // 结束的位置
        PointF pointF3 = new PointF(mRandom.nextInt(mWidth), 0);
        // 估值器Evaluator,来控制view的行驶路径(不断的修改point.x,point.y)
        BezierEvaluator evaluator = new BezierEvaluator(pointF1, pointF2);
        // 属性动画不仅仅改变View的属性,还可以改变自定义的属性
        ValueAnimator animator = ValueAnimator.ofObject(evaluator, pointF0,
                pointF3);
        animator.addUpdateListener(new AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                // 不断改变ImageView的x,y的值
                PointF pointF = (PointF) animation.getAnimatedValue();
                loveIv.setX(pointF.x);
                loveIv.setY(pointF.y);
                loveIv.setAlpha(1 - animation.getAnimatedFraction() + 0.1f);// 得到百分比
            }
        });
        animator.setTarget(loveIv);
        animator.setDuration(3000);
        return animator;
    }

  附源码:http://download.csdn.net/detail/z240336124/9449284

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值