Android属性动画封装之快速构建动画

Android实现动画效果的方式主要有帧动画、补间动画、属性动画。关于安桌动画的基础知识可以查看这篇文章 Android属性动画完全解析

这里我要讲的是如何快速构建出一个动画效果,如下图:


如果我们用属性动画实现,其中点击男性头像后的动画效果的代码如下:

// 男生头像移到上面,水平居中
                float centerX = -mPortraitMale.getX()+ (Util.getScreenWidth(this) / 2 - mPortraitMale.getWidth() / 2);
                ObjectAnimator portraitMaleTransX = ObjectAnimator.ofFloat(mPortraitMale,
                        "translationX",0,centerX);
                portraitMaleTransX.setDuration(500);
                ObjectAnimator portraitMaleTransY = ObjectAnimator.ofFloat(
                        mPortraitMale, "translationY", 0,
                        -(mPortraitMale.getY() - mPortraitFemal.getY()));
                portraitMaleTransY.setDuration(500);
                // 女生头像移出右边,并逐渐淡出
                ObjectAnimator portraitFemaleTrans = ObjectAnimator.ofFloat(
                        mPortraitFemal, "translationX", 0, Util.getScreenWidth(this)
                                - mPortraitFemal.getX());
                portraitFemaleTrans.setDuration(500);
                ObjectAnimator portraitFemaleAlpha = ObjectAnimator.ofFloat(
                        mPortraitFemal, "alpha", 1, 0.2f);
                portraitFemaleAlpha.setDuration(500);

                // 头像列表的白色背景升起
                ObjectAnimator shieldTrans = ObjectAnimator.ofFloat(mPortraitShield,
                        "translationY", mPortraitShield.getHeight(), 0);
                shieldTrans.setDuration(200);
                shieldTrans.addListener(new BaseAnimatorListener() {
                    @Override
                    public void onAnimationStart(Animator animation) {
                        mPortraitShield.setVisibility(View.VISIBLE);
                    }
                    public void onAnimationEnd(Animator animation) {
                        mScrollView.setVisibility(View.VISIBLE); // 显示头像列表
                    }
                });

                // 头像列表从底部升起
                ObjectAnimator listTrans = ObjectAnimator.ofFloat(mScrollView,
                        "translationY", mScrollView.getHeight(), 0);
                listTrans.setDuration(500);

                AnimatorSet listAnimSet = new AnimatorSet();
                listAnimSet.play(shieldTrans).before(listTrans);

                AnimatorSet animatorSet = new AnimatorSet();
                // 把男生女生头像移到相应位置后,再弹出头像列表
                animatorSet.play(portraitMaleTransX).with(portraitMaleTransY)
                        .with(portraitFemaleTrans).with(portraitFemaleAlpha)
                        .before(listAnimSet);
                animatorSet.start();

其实这个效果不难实现,可代码看上去却比较凌乱臃肿,所以,我对属性动画进行了封装,封装后的工具类为AnimatorUtil。使用方法介绍:


1.调用AnimatorSetWrap animSetWrap = AnimatorUtil.createAnimator(); 获取属性动画的封装对象;

   调用 AnimatorUtil.createAnimator(mTimeInterpolator); 可设置默认的差值器

2.animSetWrap.play(view, duration,  propertyName, values) \\设置第一个要执行的动画

                         .with(view, duration,  propertyName, values) \\ 该动画跟play中的动画同时执行

                         .with(view, duration,  propertyName, values) \\ obj为要操作的对象,该对象动画跟play中的动画同时执行

       .then(view, duration,  propertyName, values) \\ play动画执行完后,执行第一个then中的动画

       .then(view, duration, listener, propertyName, values) \\ 第1个then动画执行完后,执行第2个then中的动画,listener为动画监听器

       .then(view, duration,  propertyName, values) \\ 第2个then动画执行完后,执行第3个then中的动画,依次类推,链式构建动画

       .then(view, duration, listener,mInterpolator, propertyName, values) \\ 第4个then动画,mInterpolator会覆盖掉默认的差值器

       .start(); \\ 执行动画


3.另外还有before()和after()方法,跟自带的属性动画的方法一样,before里的动画在play动画执行完后执行,after动画执行完后才执行play动画,即在play动画之前执行。AnimatorSetWrap中的每个动画方法都有多个重载版本,可以传入操作对象、监听器等,如上所示,方法直接可以链式调用。


AnimatorUtil的核心方法then()的实现在于,用一个List存储所有的then动画,在start()方法内部通过AnimatorSet.playSequentially(List<Animator> items)方法,使then动画按照顺序执行。关键代码如下:

 public AnimatorSetWrap then(Animator animator) {
    mAnimatorsThen.add(animator); // 存入List数组
    return this;
}
private void beforeStart() {
    mIsCanceled = false;
    handleRepeat();
    if (mHasInitThenAnim) { // 只在第一次启动时初始化
        return;
    }
    mHasInitThenAnim = true;
    if (mAnimatorsThen.size() > 0) { // 拼接List数组中的动画,按顺序执行
        AnimatorSet set = new AnimatorSet();
        set.playSequentially(mAnimatorsThen);
        mAnimatorSetBuilder.before(set); // play/with动画执行完成后,再执行then动画

    }
}

public void start() {
    beforeStart();
    mAnimatorSet.start();
}



下面是使用AnimatorUtil工具类构建上图动画的代码:

float portraitMaleX = -mPortraitMale.getX()+ (Util.getScreenWidth(this) / 2 - mPortraitMale.getWidth() / 2);
float portraitMaleY = -(mPortraitMale.getY() - mPortraitFemal.getY());
AnimatorUtil.createAnimator()
        .play(mPortraitMale, ANIM_DEFAULT_DURATION, "translationX", 0,
                portraitMaleX)
        .with(mPortraitMale, ANIM_DEFAULT_DURATION, "translationY", 0,
                portraitMaleY)
        .with(mPortraitFemal, ANIM_DEFAULT_DURATION,
                "translationX", 0,
                Util.getScreenWidth(this) - mPortraitFemal.getX())
        .with(mPortraitFemal, ANIM_DEFAULT_DURATION, "alpha",
                1, 0.2f)
        .then(mPortraitShield,
                ANIM_SHIELD_DURATION,
                new AnimatorListenerAdapter() {
                    public void onAnimationStart(
                            Animator animation) {
                        mPortraitShield.setVisibility(View.VISIBLE);
                    }

                    public void onAnimationEnd(
                            Animator animation) {
                        mScrollView.setVisibility(View.VISIBLE);
                    }
                }, "translationY", mPortraitShield.getHeight(),
                0)
        .then(mScrollView, ANIM_DEFAULT_DURATION,"translationY", mScrollView.getHeight(), 0)
       .start;

可以看出代码简洁明了,构建动画便捷,如果要新增加动画效果,在相应方法后面加入动画即可。

实践中会不断的改进的代码,请大家关注最新完整的代码:https://github.com/1993hzw/Androids

  


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章