Scenes(场景)对象中封装了一个view hierarchy的状态,包括它的视图以及属性值。Transition框架可以在两个不同的Scene之间执行一个动画---这两个Scene一个被定义为起始Scene,一个被定义为终点Scene。通常系统会自动将当前屏幕所展示的视图信息当做起始Scene,而对于终点Scene,系统允许我们通过两种方式创建:加载xml配置文件或者动态new Scene对象并传入ViewGroup对象。
注意:Scene(对象)对系统执行一个动画来说并不是一个必要条件,即使没有Scene对象,系统也可以执行某一动画,对于这一点下一节讲执行一个Transition会详细讲解。然而这一节我们重点关注创建并使用Scene,也是理解Transition的精髓。
加载xml配置文件创建Scene对象
你可以通过加载一个layout布局文件来直接生成一个Scene对象,这个Scene对象中就封装了它被创建时所传入的view hierarchy的状态信息。如果在此view被改变,则需要重新创建Scene。当通过加载layout布局文件来生成Scene对象时,系统会自动将整个布局文件的view视图传给Scene。
有的童鞋可能会问:我可不可以只加载某layout布局中的部分布局来生成Scene对象呢? 你猜 ???
那如何加载layout布局文件来生成Scene对象呢?在Scene.java中有一个静态方法getSceneForLayout,通过此方法就可以加载布局文件并返回Scene对象,但是需要我们传入三个参数,依次是:
第1个参数:被创建Scene中所有view hierarchy的根视图(Root View)
第2个参数:需要被加载到Scene对象中的布局文件ID
第3个参数:上下文对象Context
定义需要被加载到Scene中的布局文件
以下两个代码片段,展示了两个不同的布局文件,这两个文件包含了如下信息:
1)main布局中包含了一个文本信息和一个用来展示Scene的根布局FrameLayout
2)一个用来生成first scene的相对布局文件,其中包含了两个TextView
3)一个用来生成second scene的相对布局文件,也包含了两个TextView但是顺序与第一个相反。 具体代码如下:
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>
加载布局文件生成Scene对象
当layout布局文件定义好之后,就可以通过加载这两个不同的文件来生成不同的Scene对象了。但是在获取Scene对象之前,必须先获取一个View对象来充当Scene对象的根视图参数。如下所示:
private FrameLayout sceneRoot;
sceneRoot = ((FrameLayout) findViewById(R.id.transitContainer));
根视图sceneRoot有了之后,就可以调用Scene.getSceneForLayout方法来生成Scene对象了。代码如下:
//获取需要通过动画展示的两个场景
Scene scene1 = Scene.getSceneForLayout(sceneRoot, R.layout.a_scene, this);
Scene scene2 = Scene.getSceneForLayout(sceneRoot, R.layout.b_scene, this);
通过以上代码,我们通过加载Layout布局文件创建了两个Scene对象。
在java代码中动态new Scene对象
除了加载layout布局文件生成Scene对象之外, 我们还可以动态的调用构造器方法(Scene(sceneRoot, viewHierarchi))new Scene对象。从红色字体的构造器可以看出,我们也需要创建view sceneRoot对象来充当Scene的根视图,具体的完整代码如下:
Scene mScene;
// Obtain the scene root element
mSceneRoot = (ViewGroup) mSomeLayoutElement;
// Obtain the view hierarchy to add as a child of
// the scene root when this scene is entered
mViewHierarchy = (ViewGroup) someOtherLayoutElement;
// Create a scene
mScene = new Scene(mSceneRoot, mViewHierarchy);