前面一篇文章讲解了Android动画Animator,但是不知道你有没有发现,前面讲解的所有的动画都是针对某一Object来进行的,虽然我们可以对整个Layout添加动画效果,但这是先把整个layout看成一个整体,再对这个整体添加动画效果。当我们想同时对多个Object添加动画效果时又该怎么做呢?
先来看一下效果
一个Scene保存了一个ViewGroup中所有元素的状。同时他还拥有一个关于这个ViewGroup的父ViewGroup的引用,这个父ViewGroup称为scene root。
关于动画的信息都存在一个Transition 对象中。通过 TransitionManager 使用Transition中动画。Transitions 框架可以在两个不同的Scene或者同一Scene的不同元素之间使用动画。
Scene mAScene;
Scene mAnotherScene;
// Create the scene root for the scenes in this app
mSceneRoot = (ViewGroup) findViewById(R.id.scene_root);
// Create the scenes
mAScene = Scene.getSceneForLayout(mSceneRoot, R.layout.a_scene, this);
mAnotherScene =
Scene.getSceneForLayout(mSceneRoot, R.layout.another_scene, this);
Transitions 框架允许自定义进入和退出Scene时的Action。把自定义的Action定义成Runnable对象并把他们作为参数传到Scene.setExitAction() 或者 Scene.setEnterAction() 中。系统会在进入和退出的时候调用这两个方法。
步骤如下:
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 mFadeTransition = new Fade();
TransitionManager.go(mEndingScene, mFadeTransition);
通过这一条语句,scene root中的View就会从初始状态根据Transition 变为结束状态。
由于Transition框架并不是对所有的对象都适用(比如ListView ),所以有时我们需要指定使用Transition的对象。
每一个使用Transition的对象叫做一个target,当然这个对象需要在Scene中。可以通过在开始transition前调用 removeTarget() 方法去除不支持的对象或者调用addTarget()来添加对象。
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。
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) {}
}
框架会对开始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());
}
...
}
@Override
public void captureEndValues(TransitionValues transitionValues) {
captureValues(transitionValues);
}
与captureStartValues()类似,把结束的值放入TransitionValues 的Map对象中,captureEndValues()中的Map对象与captureStartValues()中的Map不是同一个对象,put()的时候请放心~
创建一个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ㄒ)/~~
参考示例