活动的用户界面经常因用户输入和其他事件而变化。例如,包含用户可以键入搜索查询的窗体的活动可以在用户提交时隐藏窗体,并在其位置显示搜索结果列表。
为了在这些情况下提供视觉连续性,您可以在用户界面的不同视图层次之间进行动画转换。这些动画给用户反馈他们的行动,并帮助他们了解你的应用程序如何工作。
Android包含了转换框架,使您能够轻松地在两个视图层次之间进行动画转换。该框架将视图通过改变他们的一些属性值在运行时。该框架包括内置的动画效果,让您共同创建自定义动画和过渡生命周期回调。
转换框架
动画你的应用程序的用户界面提供不仅仅是视觉吸引力。动画突出的变化,并提供视觉线索,帮助用户了解您的应用程序的工作原理。
为了帮助你在一个视图层次和另一个视图层次之间进行动画化,Android提供了转换框架。
框架功能 | 解释 |
---|---|
组级动画(Group-level)—-不会翻译。。。 | 将一个或多个动画效果应用于视图层次结构中的所有视图。 |
过渡动画(Transition-based) | 根据开始和结束视图属性值之间的更改运行动画。 |
嵌入动画(Built-in) | 包括预定义的动画共同效果,如淡出或运动。 |
资源文件的支持 | 从布局资源文件加载视图层次结构和内置动画。 |
生命周期回调 | 定义回调以便更好地控制动画的层次变化过程 |
场景(Scenes)
场景存储视图层次结构的状态,包括所有视图及其属性值。视图层次结构可以是简单视图,也可以是视图和子布局的复杂树。在场景中存储视图层次结构状态可以使您从另一个场景过渡到该状态。框架提供场景类来表示场景。
转换框架让你创建场景布局资源文件或从你的代码中的ViewGroup对象。如果动态生成视图层次结构,或者在运行时修改视图层次结构,则在代码中创建场景非常有用。
在大多数情况下,您不创建显式的开始场景。如果您应用了一个过渡,该框架使用以前的结束场景作为任何后续转换的开始场景。如果没有应用过渡,则框架将从当前屏幕状态收集有关视图的信息。
一个场景也可以定义自己的动作,当你做一个场景改变。例如,此功能在转换到场景后用于清理视图设置非常有用。
除了视图层次结构和它的属性值,场景还存储视图层次结构的父的引用。此根视图称为场景根。场景场景中的场景和动画的更改发生在场景根中。
转换(Transitions)
在转换框架中,动画创建了一系列帧,用来描述开始和结束场景中视图层次之间的变化。有关动画的信息存储在转换对象中。动画的运行,你将使用transitionmanager实例过渡。该框架可以转换两个不同的场景或过渡到当前场景的不同状态。
该框架包括一组内置的转换常用的动画效果,如褪色和调整大小的视图。还可以自定义自定义转换,以在动画框架中使用api创建动画效果。转换框架还允许您在包含一组单独内置或自定义转换的转换集中组合不同的动画效果。
过渡生命周期与活动生命周期类似,它表示框架在动画的开始和完成之间监视的过渡状态。在重要的生命周期状态中,框架调用回调方法,您可以实现在过渡的不同阶段对用户界面进行调整。
限制
- 适用于动画SurfaceView可能无法正确显示。 SurfaceView实例是从非UI线程更新,因此更新可以是不同步的其他视图的动画。
- 当应用于某些特定的过渡类型,可能不产生期望的动画效果如TextureView。
- 扩展类AdapterView,比如 ListView,在与该过渡框架不兼容的方式管理他们的child的视图。如果您尝试动画基于视图 AdapterView,设备显示可能会挂起。
- 如果你试图调整一个TextView的动画,文字会弹出到一个新位置之前的对象已经完全调整。若要避免此问题,请不要动画包含文本的视图大小调整。
创建一个Scene
从布局文件创建Scene
您可以直接从布局资源文件中创建一个Scene的实例。文件中的视图层次是大多是静态的使用这种技术。他生成的场景表示在创建场景实例时视图层次结构的状态。如果更改视图层次,你必须重新创建场景。该框架创建一个从文件中的整个视图层次的场景; 你不能在一个布局文件的一部分创建场景。
要创建一个在布局资源文件的Scene,从布局的检索场景根ViewGroup实例,然后调用 Scene.getSceneForLayout()与场景根和包含场景的视图层次布局文件的资源ID的方法。
在Layout定义Scenes
本例包括以下布局定义:
1. 有文本标签的主布局和一个子布局。
2. 具有两个文本字段的第一场景的相对布局。
3. 具有相同的两个文本字段但是文字不同的第二场景的相对布局。
res/layout/activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/master_layout">
<TextView
android:id="@+id/title"
...
android:text="Title"/>
<FrameLayout
...
android:id="@+id/scene_root">
<include layout="@layout/a_scene" />
</FrameLayout>
</LinearLayout>
res/layout/a_scene.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/scene_container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
...
android:id="@+id/text_view1
android:text="Text Line 1" />
<TextView
...
android:id="@+id/text_view2
android:text="Text Line 2" />
</RelativeLayout>
res/layout/another_scene.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/scene_container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/text_view2
android:text="Text Line 2" />
<TextView
android:id="@+id/text_view1
android:text="Text Line 1" />
</RelativeLayout>
从Layouts生成Scenes
Scene mAScene;
Scene mAnotherScene;
//创建scene root
mSceneRoot = (ViewGroup) findViewById(R.id.scene_root);
//创建scenes
mAScene = Scene.getSceneForLayout(mSceneRoot,R.layout.a_scene, this);
mAnotherScene =Scene.getSceneForLayout(mSceneRoot,R.layout.another_scene, this);
这两个场景的使用由scene root决定。
代码中创建Scene
Scene mScene;
//获得scene root元素
mSceneRoot = (ViewGroup) mSomeLayoutElement;
//当这个场景进入的时候scene root增加子布局
mViewHierarchy = (ViewGroup) someOtherLayoutElement;
//创建scene
mScene = new Scene(mSceneRoot, mViewHierarchy);
创建Scene动作
该框架允许您定义系统在进入或退出场景时运行的自定义场景操作。在许多情况下,定义自定义场景中的动作是不必要的,因为框架动画场景之间的变化是自动的。
场景操作对于处理这些案例是有用的:
1. 不在同一层次中的动画视图。您可以使用开始和结束场景的动画视图使用退出和入口场景操作。
2. 动画视图转换动画框架不能自动,如ListView对象。有关更多信息,请参见。
为了提供自定义场景的动作,将Runnable对象,传给 Scene.setExitAction() or Scene.setEnterAction()方法。
使用Transition
在转换框架中,动画创建了一系列帧,用来描述开始和结束场景中视图层次之间的变化。该框架表示这些动画作为过渡对象,其中包含有关动画的信息。若要运行动画,则向过渡管理器提供使用和结束场景的转换。
创建Transition
在上面讲述了如何创建表示不同视图层次状态的Scene。一旦定义了要在其中更改的开始场景和结束场景,则需要创建定义动画的转换对象。如
内置转换类型(Built-in):
Class | Tag | Attributes | Effect |
---|---|---|---|
AutoTransition | < autoTransition/> | - | 默认的转换。淡出,移动和调整大小,并按顺序淡出视图。 |
Fade | < fade/> | android:fadingMode=”[fade_in,fade_out,fade_in_out]” | fade_in 淡入, fade_out淡出, viewsfade_in_out先淡出后淡入 |
ChangeBounds | < ChangeBounds/> | - | 移动和调整大小的视图 |
在资源文件中创建transition
此技术使您能够修改您的转换定义,而不必更改活动的代码。此技术也可以从应用程序代码中分离复杂的转换定义,如在指定多个转换中所示。
若要指定资源文件中的内置转换,请按照下列步骤执行:
1. 添加res/transition/ 在你的项目里。
2. 创建xml在目录里。
3. 为内置转换添加xml。
例如:
<fade xmlns:android="http://schemas.android.com/apk/res/android" />
下面是如何获得资源文件。
Transition mFadeTransition =
TransitionInflater.from(this).
inflateTransition(R.transition.fade_transition);
在代码中创建transition
Transition mFadeTransition = new Fade();
应用transition
做一个场景变化而过渡响应你的活动事件的应用,调用静态方法 TransitionManager.go()
TransitionManager.go(mEndingScene, mFadeTransition);
选择特定的目标视图
该框架适用于默认情况下开始和结束场景中所有视图的转换。在某些情况下,您可能只希望将动画应用于场景中的视图子集。例如,框架不支持动画更改ListView的对象,所以你不应该在这应用一个过渡动画。该框架使您可以选择要动画的特定视图。
每个视图过渡动画称为目标。只能选择与场景相关联的视图层次结构的一部分的目标。
从目标列表中删除一个或多个视图,叫removeTarget()方法开始前的过渡。只添加视图您指定的目标列表,调用addTarget()方法。
指定多个转换
<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>
没有scene下使用transition
在一个单一的试图层级里创建transition,按照这些步骤:
1. 当事件触发了转换过渡,调用 TransitionManager.beginDelayedTransition()方法提供给父布局的全部视图。框架存储子视图的当前状态及其属性值。
2. 根据您的用例要求更改子视图。框架记录您对子视图及其属性所做的更改。
3. 当系统重绘根据更改用户界面的框架,动画的原始状态和新状态之间的变化。
例子:
private TextView mLabelText;
private Fade mFade;
private ViewGroup mRootView;
...
//加载布局
this.setContentView(R.layout.activity_main);
...
mLabelText = new TextView();
mLabelText.setText("Label");
//获取root view和创建transition
mRootView = (ViewGroup) findViewById(R.id.mainLayout);
mFade = new Fade(IN);
TransitionManager.beginDelayedTransition(mRootView, mFade);
mRootView.addView(mLabelText);
创建自定义转换
自定义转换,如内置的转换类型之一,将动画应用到开始和结束场景的子视图中。然而,与内置的转换类型不同,您必须提供捕获属性值并生成动画的代码。您还可以为动画定义一个目标视图子集。
继承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) {}
}
获取view属性值
转场动画使用了属性动画系统。属性动画通过更改View的属性实现了属性动画,所以转场框架需要使用属性的启动值与结束值来构造动画。
属性动画通常只会用到View的极少属性。比如,颜色动画需要颜色属性值,平移动画需要位置属性值。因为转场动画只需要某些特定的属性值,所以转场框架并没有将所有的属性值提供给转场动画。相反的,转场框架会调用回调方法以便允许转场动画获得需要的属性值,并将其存入框架中。
获得起始值
为了可以将起始的View值传给转场框架,需要实现captureStartValues(transitionValues)方法。转场框架会在每个View处于启动场景时调用该方法。这个方法的参数是一个TransitionValues对象,这个对象包含了View的引用及一个Map对象,你可以将View的属性值存放在这个Map对象中,然后这些值就会被传给转场框架。
为了确保所存储的属性值的键不会与其它TransitionValues的键相冲突,可以使用以下命名规则:
package_name:transition_name:property_name
public class CustomTransition extends Transition {
private static final String PROPNAME_BACKGROUND =
"com.example.android.customtransition:CustomTransition:background";
@Override
public void captureStartValues(TransitionValues transitionValues) {
captureValues(transitionValues);
}
// For the view in transitionValues.view, get the values you
// want and put them in transitionValues.values
private void captureValues(TransitionValues transitionValues) {
View view = transitionValues.view;
transitionValues.values.put(PROPNAME_BACKGROUND, view.getBackground());
}
...
}
获取结束值
@Override
public void captureEndValues(TransitionValues transitionValues) {
captureValues(transitionValues);
}
创建自定义animator
为了使View在转场的时候可以以动画的方式变动,需要重写createAnimator()方法,并返回一个Animator对象。在转场框架调用这个方法时,会将转换场景的根View与TransitionValues对象传回。启动TransitionValues对象包含了转场过程中所捕获的属性值。
createAnimator()方法的调用取决于启动场景与结束场景变换的过程。试着将淡入淡出动画想象为自定义转场动画。如果启动场景有5个target,而到了结束场景时被移除了两个,并且还添加了一个新的target,那么转场框架会调用createAnimator()方法6次:其中三个在启动场景与结束场景中都在出现,其中两个在转变到结束场景的过程中被移除了,最后一个在转换到结束场景时被添了进去。
对于在开始场景与结束场景中都存在的target View,转场框架会在调用createAnimator()方法时将TransitionValues对象通过startValues参数与endValues参数回传。对于只存在于单个场景的target View,转场框架会通过对应的参数将TransitionValues对象回传,而另一个参数则为空。
在实现createAnimator(ViewGroup, TransitionValues, TransitionValues)方法时,使用所捕获的属性值来创建一个Animator对象,并将其返回给转场框架。对于实现的示例,请参见CustomTransition示例中的ChangeColor类。有关更多属性动画的相关信息,请参见Property Animation。