一 效果图

android仿送礼特效 送礼物特效_BezierEvaluator


android仿送礼特效 送礼物特效_AnimatorSet_02

二 视频送礼物,冒泡泡效果

1 需求

  • 点击显示礼物图片
  • “礼物”由无到有,由小到大,由透明到变实
  • “礼物”从底部到顶部逐渐平滑“上浮”,然后消失

2 分析

  • 自定义ViewGroup显示,“礼物”是一个ImageView,通过addView显示
  • 动画实现 从小到大,从透明变实
  • 平滑上浮的轨迹用贝赛尔算法控制ImageView的Point
  • 贝赛尔曲线的起始 和终止点在底部居中和顶部任意位置,第二和第三个锚点在屏幕中,通常第三个的位置高于第二个

3 主要代码

贝赛尔算法:

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 point0, PointF point3) {
        PointF point = new PointF();
        point.x = point0.x * (1 - t) * (1 - t) * (1 - t)
                + 3 * pointF1.x * t * (1 - t) * (1 - t)
                + 3 * pointF2.x * t * t * (1 - t)
                + point3.x * t * t * t;

        point.y = point0.y * (1 - t) * (1 - t) * (1 - t)
                + 3 * pointF1.y * t * (1 - t) * (1 - t)
                + 3 * pointF2.y * t * t * (1 - t)
                + point3.y * t * t * t;
        return point;
    }
}

自定义的ViewGroup

public class LoveLayout extends RelativeLayout {


    private Interpolator line = new LinearInterpolator();//线性
    private Interpolator acc = new AccelerateInterpolator();//加速
    private Interpolator dce = new DecelerateInterpolator();//减速
    private Interpolator accdec = new AccelerateDecelerateInterpolator();//先加速后减速
    private Interpolator[] interpolators;


    Drawable[] drawables = new Drawable[3];
    private Random random = new Random();
    private int dHeight;
    private int dWidth;
    private LayoutParams params;
    private int mWidth;
    private int mHeight;

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

    public LoveLayout(Context context) {
        super(context);
        init();
    }

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

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

    private void init() {
        interpolators = new Interpolator[4];
        interpolators[0] = line;
        interpolators[1] = acc;
        interpolators[2] = dce;
        interpolators[3] = accdec;

        //准备图片集合
        drawables[0] = getResources().getDrawable(R.drawable.red);
        drawables[1] = getResources().getDrawable(R.drawable.yellow);
        drawables[2] = getResources().getDrawable(R.drawable.blue);
        //得到图片的原始高度
        dWidth = drawables[0].getIntrinsicWidth();
        dHeight = drawables[0].getIntrinsicHeight();
        params = new LayoutParams(dWidth, dHeight);
        //将iv添加到父容器底部、水平居中位置
        params.addRule(CENTER_HORIZONTAL);
        params.addRule(ALIGN_PARENT_BOTTOM);
    }

    public void addLoveIcon() {
        //添加心形,并开始执行动画
        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();
    }

    // 得到一个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 enter = new AnimatorSet();
        enter.setDuration(600);
        enter.playTogether(alpha, scaleX, scaleY);
//		enter.setTarget(iv);

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

        AnimatorSet set = new AnimatorSet();
        //按序列执行
        set.playSequentially(enter, bezierAnimator);
        //加速因子,使用插值器
        set.setInterpolator(interpolators[random.nextInt(4)]);
        set.setTarget(iv);
        return set;
    }

    //得到一个贝塞尔曲线动画
    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 evaluator = new BezierEvaluator(pointF1, pointF2);
        //属性动画不仅仅可以改变view的属性,还可以改变自定义的属性(比如Point)
        ValueAnimator animator = ValueAnimator.ofObject(evaluator, pointF0, pointF3);
        animator.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());//1~0 百分比
            }
        });

        animator.setDuration(4000);
        return animator;
    }

    private PointF getPointF(int i) {
        PointF pointF = new PointF();
        pointF.x = random.nextInt(mWidth);
        //为了好看,尽量保证point2.y>point1.y
        if (i == 1) {
            pointF.y = random.nextInt(mHeight / 2) + mHeight / 2;
        } else {
            pointF.y = random.nextInt(mHeight / 2);
        }
        return pointF;
    }
}

4 Demo

GiftActivity

三 淘宝商品折叠效果

1 需求

  • 页面分两部分,上面的商品图片和下面显示部分的详情
  • 点击时,图片翻转缩小,详情部分上滑显示更多内容

2 分析

  • 两个部分用两个ViewGroup
  • 翻转缩小动画控制第一个ViewGroup显示图片
  • 上滑动画控制显示第二个ViewGroup显示详情

3 主要代码

public void startFirstAnim(View v){
        //显示first_view:1.透明度动画;2.缩放动画;3.翻转动画
        //透明度动画
        ObjectAnimator firstAlphaAnim = ObjectAnimator.ofFloat(first_view, "alpha", 1.0f, 0.7f);
        firstAlphaAnim.setDuration(300);
        //旋转动画1
        ObjectAnimator firstRotationXanim = ObjectAnimator.ofFloat(first_view, "rotationX", 0f,20f);
        firstRotationXanim.setDuration(300);
        //再旋转回来
        ObjectAnimator firstResumeRotationXanim = ObjectAnimator.ofFloat(first_view, "rotationX", 20f, 0f);
        firstResumeRotationXanim.setDuration(300);
        firstResumeRotationXanim.setStartDelay(300);//延迟第一次旋转动画的时间,在这之后再执行

        //缩放动画
        ObjectAnimator firstScaleXAnim = ObjectAnimator.ofFloat(first_view, "ScaleX", 1.0f, 0.8f);
        firstScaleXAnim.setDuration(300);
        ObjectAnimator firstScaleYAnim = ObjectAnimator.ofFloat(first_view, "ScaleY", 1.0f, 0.8f);
        firstScaleYAnim.setDuration(300);

        //由于缩放造成离顶部有一个距离,需要平移
        ObjectAnimator firstTranslationYAnim = ObjectAnimator.ofFloat(first_view, "translationY", 0f, -0.1f*first_view.getHeight());
        firstTranslationYAnim.setDuration(300);

        //第二个view和第一个view动画同时开始执行
        ObjectAnimator secondTranslationYAnim = ObjectAnimator.ofFloat(second_view, "translationY", second_view.getHeight(), 0f);
        secondTranslationYAnim.setDuration(300);
//		secondTranslationYAnim.setStartDelay(200);
        secondTranslationYAnim.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                super.onAnimationStart(animation);
                second_view.setVisibility(View.VISIBLE);
                bt.setClickable(false);
            }
        });


        AnimatorSet set = new AnimatorSet();
        set.playTogether(firstScaleXAnim,firstScaleYAnim,firstAlphaAnim,firstRotationXanim,firstResumeRotationXanim,firstTranslationYAnim,secondTranslationYAnim);
        set.start();

    }

4 Demo

TaoBaoActivity