天天看點

Android Transition動畫

動畫在app中的重要性我不用多說了,在應用中使用一些符合系統設計規範的動畫可以顯著提升使用者體驗和自身逼格,我們也接觸過很多種動畫,幀動畫和屬性動畫大家應該很熟悉了,用的也比較多,今天我們要說的是

Transition

動畫,這個Api是在API 19(Android 4.4)中加入的。

為什麼要引入Transition?

由于在Android引入了Metrial Desigon之後,動畫的場面越來越大,比如以前我們制作一個動畫可能涉及到的View就一個,或者就那麼幾個,如果我們一個動畫中涉及到了目前Activity視圖樹中的各個View,那麼情況就複雜了。比如我們要一次針對視圖樹中的10個View進行動畫,這些View的效果都不同,可能有的是平移,有的是旋轉,有的是淡入淡出,那麼不管是使用之前哪種方式的動畫,我們都需要為每個View定義一個開始狀态和結束狀态【關鍵幀,比如放縮,我們得設定fromXScale和toXScale 】,随着View個數的增加,這個情況會越來越複雜。Transition主要做的事情是:

  1. 捕獲每一個 View 的起始和結束狀态
  2. 根據這些資料來建立從一個場景到另一個場景間的過渡動畫。

Transition 例子

考慮這樣一個例子,當使用者點選螢幕,讓activity中的view逐漸消失。使用安卓的transition架構,我們隻需幾行代碼就可完成,如下:

public class ExampleActivity extends Activity implements View.OnClickListener {
    private ViewGroup mRootView;
    private View mRedBox, mGreenBox, mBlueBox, mBlackBox;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRootView = (ViewGroup) findViewById(R.id.layout_root_view);
        mRootView.setOnClickListener(this);
        mRedBox = findViewById(R.id.red_box);
        mGreenBox = findViewById(R.id.green_box);
        mBlueBox = findViewById(R.id.blue_box);
        mBlackBox = findViewById(R.id.black_box);
    }
    @Override
    public void onClick(View v) {
        TransitionManager.beginDelayedTransition(mRootView, new Fade());
        toggleVisibility(mRedBox, mGreenBox, mBlueBox, mBlackBox);
    }
    private static void toggleVisibility(View... views) {
        for (View view : views) {
            boolean isVisible = view.getVisibility() == View.VISIBLE;
            view.setVisibility(isVisible ? View.INVISIBLE : View.VISIBLE);
        }
    }
}
           

為了更好的了解幕後發生的事情,讓我們來一步一步的分析,假設最開始每個view都是可見的:

  1. 當點選事件發生之後調用TransitionManager的beginDelayedTransition()方法,并且傳遞了mRootView和一個Fade對象最為參數。之後,framework會立即調用transition類的captureStartValues()方法為每個view儲存其目前的可見狀态(visibility)。
  2. 當beginDelayedTransition傳回之後,在上面的代碼中将每個view設定為不可見。
  3. 在接下來的顯示中framework會調用transition類的captureEndValues()方法,記錄每個view最新的可見狀态。
  4. 接着,framework調用transition的createAnimator()方法。transition會分析每個view的開始和結束時的資料發現view在開始時是可見的,結束時是不可見的。Fade(transition的子類)會利用這些資訊建立一個用于把view的alpha屬性變為0的AnimatorSet,并且将此AnimatorSet對象傳回。
注意: 讀者可以在這裡回想假如不使用transition架構,我們自己使用屬性動畫(Animator)來實作是不是複雜很多,其實transition架構的作用就是封裝了屬性動畫的操作。

這個簡單的例子強調了transition架構的兩個主要優點。第一、Transitions抽象和封裝了屬性動畫,Animator的概念對開發者來說是透明的,是以它極大的精簡了代碼量。開發者所做的所有事情隻是改變一下view前後的狀态資料,Transition就會自動的根據狀态的差別去生成動畫效果。第二、不同場景之間變換的動畫效果可以簡單的通過使用不同的Transition類來改變,本例中用的是Fade。

Android Transition動畫

實作上圖中的那兩個不同的動畫效果可以将Fade替換成Slide或者Explode即可。在接下來的文章中你将會發現,這些優點将使得我們隻用少量代碼就可以建立複雜的Activity 和Fragment切換動畫。在接下來的小節中,将看到是如何使用Lollipop的Activity 和Fragment transition API來實作這種變換的。

5.0中的Activity和Fragment Transition

Android 5.0中Transition可以被用來實作Activity或者Fragment切換時的異常複雜的動畫效果。雖然在以前的版本中,已經可以使用Activity的overridePendingTransition() 和 FragmentTransaction的setCustomAnimation()來實作Activity或者Fragment的動畫切換,但是他們僅僅局限與将整個視圖一起動畫變換。新的Lollipop api更進了一步,讓單獨的view也可以在進入或者退出其布局容器中時發生動畫效果,甚至還可以在不同的activity/Fragment中共享一個view。

在開始講解之前我們先做一些約定,雖然下面的約定是針對activity的,但是在Fragment中也是一樣的約定。

A和B分别是兩個Activity,假設activity A 調用activity B。将A代表調用Activity ,B代表被調用Activity。

Activity transition API圍繞退出(exit),進入(enter),傳回(return)和再次進入(reenter)四種transition。按照上面對A和B的約定,我這樣描述這一過程。

Activity A的退出變換(exit transition)決定了在A調用B的時候,A中的View是如何播放動畫的。

Activity B的進入變換(enter transition)決定了在A調用B的時候,B中的View是如何播放動畫的。

Activity B的傳回變換(return transition)決定了在B傳回A的時候,B中的View是如何播放動畫的。

Activity A的再次進入變換(reenter transition)決定了在B傳回A的時候,A中的View是如何播放動畫的。

最後framework提供了兩種Activity transition- 内容transition和共享元素的transition:

A content transition determines how an activity’s non-shared views—called transitioning views—enter or exit the activity scene.

A shared element transition determines how an activity’s shared elements (also called hero views) are animated between two activities.

Android Transition動畫

上圖中示範了Google Play Newsstand 應用的效果,雖然我們無法檢視它的源碼,但是我敢打賭它用了以下的transition:

activity A 中exit和reenter transition是為null的,因為A中的非共享view在退出和再次進入的時候沒有動畫效果。

activity B中的enter content transition使用了自定義的slide-in變換。該變換使B中list的元素從下到上過度。

activity B中return content transition是一組TransitionSet,同時播放了兩個子元素的變換:上半部分和下半部分的slide變換。看起來就像整個界面被從從中間分割成了兩半。

enter and return 共享元素變換是用了ChangeImageTransform。讓兩個activity中的ImageView無縫切換。

Activity Transition API介紹

用5.0的API建立一個基本的Activity transition是較為簡單的。下面的總結是實作Activity transition的步驟。這篇文章主要是對Activity transition做簡單的介紹,作為引入的篇章。在後續的文章中我們再介紹一些進階的用法。

  • 在調用與被調用的activity中,通過設定Window.FEATURE_ACTIVITY_TRANSITIONS 和 Window.FEATURE_CONTENT_TRANSITIONS 來啟用transition api ,可以通過代碼也可以通過設定主題來啟用:

代碼方式,在setContentView之前調用:

主題xml:

<item name="android:windowContentTransitions">true</item>
           
  • 分别在調用與被調用的activity中設定exit 和enter transition。Material主題預設會将exit的transition設定成null而enter的transition設定成Fade .如果reenter 或者 return transition沒有明确設定,則将用exit 和enter的transition替代。
  • 分别在調用與被調用的activity中設定exit 和enter 共享元素的transition。Material主題預設會将exit的共享元素transition設定成null而enter的共享元素transition設定成@android:transition/move.如果reenter 或者 return transition沒有明确設定,則将用exit 和enter的共享元素transition替代。

    開始一個activity的content transaction需要調用startActivity(Context, Bundle)方法,将下面的bundle作為第二個參數:

ActivityOptions.makeSceneTransitionAnimation(activity, pairs).toBundle();

其中pairs參數是一個數組:Pair

Fragment Transition API介紹

如果你想在Fragment中使用transition,除了一小部分差別之外和activity大體一緻:

  1. Content的exit, enter, reenter, 和return transition需要調用fragment的相應方法來設定,或者通過fragment的xml屬性來設定。
  2. 共享元素的enter和return transition也n需要調用fragment的相應方法來設定,或者通過fragment的xml屬性來設定。
  3. 雖然在activity中transition是被startActivity()和finishAfterTransition()觸發的,但是Fragment的transition卻是在其被FragmentTransaction執行下列動作的時候自動發生的。added, removed, attached, detached, shown, ,hidden。
  4. 在Fragment commit之前,共享元素需要通過調用addSharedElement(View, String) 方法來成為FragmentTransaction的一部分。

原文連結 http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0113/2310.html

相容4.4以前的開源項目位址

繼續閱讀