当前位置: 代码迷 >> Android >> Android最新动画片框架完全解析(二)——Transitions Framework(Transitions 框架)
  详细解决方案

Android最新动画片框架完全解析(二)——Transitions Framework(Transitions 框架)

热度:50   发布时间:2016-04-24 12:06:32.0
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

<fade xmlns:android="http://schemas.android.com/apk/res/android" />

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中,如下:

<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"    android:transitionOrdering="sequential">    <fade android:fadingMode="fade_out" />    <changeBounds />    <fade android:fadingMode="fade_in" /></transitionSet>

在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ㄒ)/~~

  相关解决方案