使用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" />
...

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

transition_01

transition_02

为了看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的效果:

transition_03

为什么会产生这样的效果呢?因为如果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/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值