天天看点

使用Android.Transition框架创建动画(1)

在Android 4.4(KitKat)中,谷歌添加了很多不错的东西。现在我们来看看android.transition框架。

多年来,android不断改进现有的动画工具供开发者使用。在HoneyComb版本中,提供了很多不错的API用于创建丰富、复杂的动画。在此基础上,KitKat的android.transition让我们可以通过一种更直观的方式定义动画效果。

Scene和Transition

先从Scene和Transition概念说起。Scene定义了界面的当前状态信息,而Transition定义了界面之间的切换。

可以从布局文件中载入Scene定义,示例如下:

1

scene = Scene.getSceneForLayout(container, R.layout.example, context);

其中

container

在Scene中是一个包含了所有view的ViewGroup。如果是在fragment中,Scene就是传入

onCreateView()

方法的参数。使用Transition的最简单方式就是使用

TransitionManager

处理,示例如下:

1

TransitionManager.go(scene);

如果在

TransitionManager

中不明确需要指定哪个Transition,就会默认使用

AutoTransition

,这个我们会后面介绍。也可以用

inflater

载入现有的view来创建Scene,示例如下:

1 2

View view = inflater.inflate(R.layout.example, container,

false

);

Scene scene =

new

Scene(container, (ViewGroup)view);

Andorid.Transition实践

我们来看一个更详细的示例,首先从项目主页下载示例代码AndroidTransitionExample。这已经是一个已完成的项目了,所以也可以用

git checkout

检出代码(以下是详细解释)。

首先新建只包含一个Fragment的项目,这样可以更容易记录一些信息。我们为

TransitionFragment

新建一个xml布局文件,叫做fragment_transition_scene_1.xml。接着往里面添加一个

TextView

,然后在

TextView

下面再添加一个Button,如下:

fragment_transition_scene_1.xml

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

<

RelativeLayout

xmlns:android

=

"http://schemas.android.com/apk/res/android"

android:id

=

"@+id/scene"

android:layout_width

=

"match_parent"

android:layout_height

=

"match_parent"

>

<

TextView

android:id

=

"@+id/textView"

android:text

=

"@string/hello_world"

android:layout_width

=

"wrap_content"

android:layout_height

=

"wrap_content"

/>

<

Button

android:id

=

"@+id/goButton"

android:text

=

"@string/button_go"

android:layout_below

=

"@id/textView"

android:layout_width

=

"wrap_content"

android:layout_height

=

"wrap_content"

/> 

</

RelativeLayout

>

你一定猜得到,我们接下来还要新建另一个xml布局文件,fragment_transition_scene_2.xml。它和上一个布局文件基本一样,只是把Button移到布局底部。示例如下:

1 2 3 4 5 6 7 8 9

...

<

Button

android:id

=

"@+id/goButton"

android:text

=

"@string/button_go"

android:layout_below

=

"@id/textView"

android:layout_alignParentBottom

=

"true"

android:layout_width

=

"wrap_content"

android:layout_height

=

"wrap_content"

/>

...

这是两个布局的屏幕截图:

使用Android.Transition框架创建动画(1)
使用Android.Transition框架创建动画(1)

为了看Transition的效果,我们从第二个布局文件中创建Scene。点击goButton的时候展示Transition的效果。我们先修改一下

TransitionFragment.onCreateView()

方法的代码,如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

@Override

public

View onCreateView(LayoutInflater inflater,

ViewGroup container, Bundle savedInstanceState) {

View rootView = inflater.inflate(R.layout.fragment_transition_scene_1,

container,

false

);

final

Scene scene = Scene.getSceneForLayout(container,

R.layout.fragment_transition_scene_2, getActivity());

Button goButton = (Button)rootView.findViewById(R.id.goButton);

goButton.setOnClickListener(

new

View.OnClickListener() {       

@Override

public

void

onClick(View v) {

TransitionManager.go(scene);

}

});

return

rootView;

}

这是点击goButton的效果:

使用Android.Transition框架创建动画(1)

为什么会产生这样的效果呢?因为如果view有相同的ID,就会被当做是同一个view,然后也会被改变(通过改变bounds),也就是说,在Scene切换时,view的位置和大小也会改变,需要注意的是两个布局文件的

RelativeLayout

也要有相同的ID。

使用GIT实战

如果你对整个例子代码感兴趣的话,也可以利用GIT检出代码。从AndroidTransitionExample复制一份即可,你可以用GUI git客户端列出项目的历史版本,也可以定位到某个具体的提交点检出。

当然,你也可以使用命令行。使用

cd

命令切换到项目文件夹,然后执行以下命令:

1

git log --oneline

此时,你会得到项目的提交列表,像这样:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

cc40873 load the transition manager from the XML

file

c2a25d4 inflate the transition from the XML

file

9871bfa add the

return

transition

1de57f0 use AnticipateOvershootInterpolator

fbcc465 slow motion transitions

6ea37f7 extract method goToScene

34e0f8f restore transition by adding LinearLayout with

id

2b000b3 example of change bounds not working when changing hierarchy

6b4629c example of transitioning from Button to ImageView

092ebe0 added layout_weight to button

1e7c5be modified layout

for

scene 2

d94b907 Android Studio updated IML files

24f9a74 Create README.md

0667c36 simple transition

4265f50 factor out TransitionFragment

280f123 initial commit

以上贴出的对应于simple transition这个提交点,执行以下代码可以把项目设置成这个状态:

1

git checkout 0667c36

执行 

git checkout

 ,你可以跳到任意一个提交点上,下面的插入文字会给出指示操作。

修改布局文件

我们来修改一下第二个布局文件,首先把

RelativeLayout

换成

LinearLayout

,然后我们来介绍一个在第一个布局文件中没有出现的view,最后我们重新排布一下这些view,代码如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

<

LinearLayout

xmlns:android

=

"http://schemas.android.com/apk/res/android"

android:id

=

"@+id/scene"

android:layout_width

=

"match_parent"

android:layout_height

=

"match_parent"

android:orientation

=

"vertical"

android:gravity

=

"center_horizontal"

>  

<

TextView

android:id

=

"@+id/textView"

android:text

=

"@string/hello_world"

android:layout_weight

=

"1"

android:layout_width

=

"wrap_content"

android:layout_height

=

"wrap_content"

/>       

<

TextView

android:text

=

"@string/hello_world"

android:layout_weight

=

"1"

android:layout_width

=

"wrap_content"

android:layout_height

=

"wrap_content"

/>       

<

Button

android:id

=

"@+id/goButton"

android:text

=

"@string/button_go"

android:layout_width

=

"wrap_content"

android:layout_height

=

"wrap_content"

/> 

</

LinearLayout

>

我们目前处于“1e7c5be modified layout for scene 2”提交点,在命令行执行

git checkout 1e7c5be

就可以切换上去。可以看到,Transition仍然起作用,在第一个Scene里面,不存在的view竟然出现在屏幕上,然后随着Button和TextView的移动而逐渐消失。

我们详细看看AutoTransition,事实证明,它只是

TransitionSet

的子类,只是它给自己定义了一个执行序列,分别是fading out、changing bounds、fading in。

我们注意到,在第二个Transition中,AutoTransition会改变bounds,目前我们只看到了Button和TextView改变了位置,如果我们改变view的大小会出现什么情况呢?在Button中添加layout_weight属性来看看效果:

1 2 3 4 5 6

<

Button

android:id

=

"@+id/goButton"

android:text

=

"@string/button_go"

android:layout_weight

=

"1"

android:layout_width

=

"wrap_content"

android:layout_height

=

"wrap_content"

/>

现在Button在转变的过程中既改变了位置也改变了大小。

现在切换到“added layout_weight to button”这个点,命令:

git checkout 092ebe0

。现在再做一些变化效果,在Scene中把Button转变成

ImageView

1 2 3 4 5 6 7

<

ImageView

android:id

=

"@+id/goButton"

android:text

=

"@string/button_go"

android:layout_weight

=

"1"

android:src

=

"@drawable/bnr_hat"

android:layout_width

=

"wrap_content"

android:layout_height

=

"wrap_content"

/>

此时切换到“example of transitioning from Button to ImageView”这个点,命令: 

git checkout 6b4629c

。看看从Button变成

ImageView

的效果:

仔细看你会发现,第一个Button首先被一张切割过的图片替换了,然后逐渐移动到最终的位置,逐渐改变大小。

如果我们改变所有views的嵌套结构,比如在Button外面套一层

LinearLayout

,那么Bounds就不会改变了。transition manager要求在Scene的布局文件中,同一层级的view要有和之前相同的ID:

1 2 3 4 5 6 7 8 9 10 11 12 13

<

LinearLayout

android:layout_width

=

"match_parent"

android:layout_height

=

"wrap_content"

>

<

ImageView

android:src

=

"@drawable/bnr_hat"

android:layout_width

=

"wrap_content"

android:layout_height

=

"wrap_content"

/>

<

Button

android:id

=

"@+id/goButton"

android:text

=

"@string/button_go"

android:layout_width

=

"wrap_content"

android:layout_height

=

"wrap_content"

/>

</

LinearLayout

>

此时切换到“example of change bounds not working when changing hierarchy”这个点,命令:

git checkout 2b000b3

如果我们在第一个Scene中继续用

LinearLayout

包含Button,那么还是不行。想让它起作用的话,可以给

LinearLayout

一个相同的ID。这会得到两种不同的效果。

切换到“restore transition by adding LinearLayout with id”,命令:

git checkout 34e0f8f

下一篇我们我们继续研究怎么控制Transition,以及如何从xml文件中载入Transition。

原文地址 http://blog.jobbole.com/62601/

继续阅读