Android最新動畫架構完全解析(二)——Transitions Framework(Transitions 架構)
前面一篇文章講解了Android動畫Animator,但是不知道你有沒有發現,前面講解的所有的動畫都是針對某一Object來進行的,雖然我們可以對整個Layout添加動畫效果,但這是先把整個layout看成一個整體,再對這個整體添加動畫效果。當我們想同時對多個Object添加動畫效果時又該怎麼做呢?
先來看一下效果
為什麼要使用Transitions:ViewGroup層級的動畫效果 只需確定動畫的開始和結束的狀態就可以完成整個動畫 有可以直接使用的常用動畫 支援從資源檔(Resource)載入動畫 生命週期中有回呼函數,可以更好的控制動畫效果Scenes
一個Scene儲存了一個ViewGroup中所有元素的狀。同時他還擁有一個關於這個ViewGroup的父ViewGroup的引用,這個父ViewGroup稱為scene root。
Transitions
關於動畫的資訊都存在一個Transition 對象中。通過 TransitionManager 使用Transition中動畫。Transitions 架構可以在兩個不同的Scene或者同一Scene的不同元素之間使用動畫。
限制API Level 19 (Android 4.4.2) 使用在SurfaceView上可能會出錯
SurfaceView 是在一個非UI線程上更新的,所以可能會更其他元素的動畫不同步。 使用在TextureView上可能會出錯 使用在繼承自AdapterView的View,比如ListView上可能會出錯。 當你對TextView 使用動畫的時候,裡面的文字在動畫沒有結束之前可能會跑到其他地方。建立Scene
Scene mAScene;Scene mAnotherScene;// Create the scene root for the scenes in this appmSceneRoot = (ViewGroup) findViewById(R.id.scene_root);// Create the scenesmAScene = Scene.getSceneForLayout(mSceneRoot, R.layout.a_scene, this);mAnotherScene = Scene.getSceneForLayout(mSceneRoot, R.layout.another_scene, this);
建立Scene Actions
Transitions 架構允許自訂進入和退出Scene時的Action。把自訂的Action定義成Runnable對象並把他們作為參數傳到Scene.setExitAction() 或者 Scene.setEnterAction() 中。系統會在進入和退出的時候調用這兩個方法。
建立Transition從resource檔案中建立Transition
步驟如下:
1 . 在項目中添加res/transition/目錄
2 . 在目錄中建立XML檔案
res/transition/fade_transition.xml
3 . 在Activity中載入
Transition mFadeTransition = TransitionInflater.from(this). inflateTransition(R.transition.fade_transition);
在代碼中動態添加Transition
Transition mFadeTransition = new Fade();
調用Transition
TransitionManager.go(mEndingScene, mFadeTransition);
通過這一條語句,scene root中的View就會從初始狀態根據Transition 變為結束狀態。
對特定的View使用Transition
由於Transition架構並不是對所有的對象都適用(比如ListView ),所以有時我們需要指定使用Transition的對象。
每一個使用Transition的對象叫做一個target,當然這個對象需要在Scene中。可以通過在開始transition前調用 removeTarget() 方法去除不支援的對象或者調用addTarget()來添加對象。
使用transitionSet
transitionSet類似Animation中的Set,是一個動畫集合。定義在XML中,如下:
在Activity中調用TransitionInflater.from() 來載入TransitionSet。TransitionSet繼承自Transition,能用Transition的地方都可以使用TransitionSet。
自訂Transitions繼承Transition 類
public class CustomTransition extends Transition { @Override public void captureStartValues(TransitionValues values) {} @Override public void captureEndValues(TransitionValues values) {} @Override public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) {}}
重寫captureStartValues()
架構會對開始Scene中的每一個對象調用captureStartValues()方法,方法的參數是TransitionValues 對象,這個對象包含對應這個View的一個引用和一個Map執行個體,這個Map執行個體用來儲存你需要的屬性值,為了保證屬性值的Key不與其他的TransitionValues 的Key 衝突,推薦使用如下的命名規則。
package_name:transition_name:property_name
下面是一個重寫 captureStartValues() 的例子:
public class CustomTransition extends Transition { // Define a key for storing a property value in // TransitionValues.values with the syntax // package_name:transition_class:property_name to avoid collisions private static final String PROPNAME_BACKGROUND = "com.example.android.customtransition:CustomTransition:background"; @Override public void captureStartValues(TransitionValues transitionValues) { // Call the convenience method captureValues captureValues(transitionValues); } // For the view in transitionValues.view, get the values you // want and put them in transitionValues.values private void captureValues(TransitionValues transitionValues) { // Get a reference to the view View view = transitionValues.view; // Store its background property in the values map transitionValues.values.put(PROPNAME_BACKGROUND, view.getBackground()); } ...}
captureEndValues()
@Overridepublic void captureEndValues(TransitionValues transitionValues) { captureValues(transitionValues);}
與captureStartValues()類似,把結束的值放入TransitionValues 的Map對象中,captureEndValues()中的Map對象與captureStartValues()中的Map不是同一個對象,put()的時候請放心~
createAnimator()
建立一個Animator用來負責從初始狀態到結束狀態的動畫效果,並把這個Animator返回。下面是一個改變背景顏色的例子。
// Create an animation for each target that is in both the starting and ending Scene. For each // pair of targets, if their background property value is a color (rather than a graphic), // create a ValueAnimator based on an ArgbEvaluator that interpolates between the starting and // ending color. Also create an update listener that sets the View background color for each // animation frame @Override public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) { // This transition can only be applied to views that are on both starting and ending scenes. if (null == startValues || null == endValues) { return null; } // Store a convenient reference to the target. Both the starting and ending layout have the // same target. final View view = endValues.view; // Store the object containing the background property for both the starting and ending // layouts. Drawable startBackground = (Drawable) startValues.values.get(PROPNAME_BACKGROUND); Drawable endBackground = (Drawable) endValues.values.get(PROPNAME_BACKGROUND); // This transition changes background colors for a target. It doesn't animate any other // background changes. If the property isn't a ColorDrawable, ignore the target. if (startBackground instanceof ColorDrawable && endBackground instanceof ColorDrawable) { ColorDrawable startColor = (ColorDrawable) startBackground; ColorDrawable endColor = (ColorDrawable) endBackground; // If the background color for the target in the starting and ending layouts is // different, create an animation. if (startColor.getColor() != endColor.getColor()) { // Create a new Animator object to apply to the targets as the transitions framework // changes from the starting to the ending layout. Use the class ValueAnimator, // which provides a timing pulse to change property values provided to it. The // animation runs on the UI thread. The Evaluator controls what type of // interpolation is done. In this case, an ArgbEvaluator interpolates between two // #argb values, which are specified as the 2nd and 3rd input arguments. ValueAnimator animator = ValueAnimator.ofObject(new ArgbEvaluator(), startColor.getColor(), endColor.getColor()); // Add an update listener to the Animator object. animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { Object value = animation.getAnimatedValue(); // Each time the ValueAnimator produces a new frame in the animation, change // the background color of the target. Ensure that the value isn't null. if (null != value) { view.setBackgroundColor((Integer) value); } } }); // Return the Animator object to the transitions framework. As the framework changes // between the starting and ending layouts, it applies the animation you've created. return animator; } } // For non-ColorDrawable backgrounds, we just return null, and no animation will take place. return null; }
總結
關於Android動畫的所有基本知識到此就講完了,Animation主要為了實現單個對象的動畫效果,Transitions 架構可以同時實現多個對象的動畫效果。在實際項目中還需要根據具體需求選擇。基本知識雖然講完了,但是如何?優美的效果還是很考驗美術功底的,比如說博主就是一個典型的失敗例子/(ㄒoㄒ)/~~