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

  


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