Material Design动画(二)

本文将介绍Material Design中的场景动画。 
所谓的场景,可以理解为当前布局的一个样式,而场景动画是由一个布局切换到另一个布局的动画效果。在这两个布局中,若有同样id的控件,那么将这两个布局进行以场景动画的方式切换时,系统会比较两个相同的id的控件的相对位置,并对切换过程执行属性动画。


可由如下示意图对场景动画的切换窥知一二。 
场景动画


将Starting Layout作为开始场景(Starting Scene)的布局,将Ending Layout作为结束场景(Ending Scene)的布局,通过Transition Manager管理需要相互切换的两个布局,而底层实现是属性动画。 
下面将通过一个demo浅析场景动画。


效果展示

这里写图片描述这里写图片描述


界面首先展示了一个“Hello world!”和一个“TRANSFORMATION”按钮,点击按钮,经过场景动画,切换到第二张图,按钮移到了底部,“Hello world!”平移到了中间顶部,同时多了一个红色的圆和中间的“Hello world!”。实现这个动画效果只需要按照上述流程即可。下面首先展示XML布局。


XML布局


Scene1的XML布局

首先是Scene1的布局,为简便起见,直接为button设置android:onClick属性,以便点击该button时,直接执行相应方法。


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/scene"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

    <LinearLayout
        android:id="@+id/buttonContainer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/textView">

        <Button
            android:id="@+id/goButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="goToScene2"
            android:text="@string/button_go" />

    </LinearLayout>

</RelativeLayout>
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

Scene2的XML布局

值得注意的是,第一个TextView和Button的id与Scene1中的TextView、Button的id是一模一样的,这也是场景动画最关键的一点,即需要执行动画变换的控件需要在起点与终点的布局场景中设置相同的id。


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/scene"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.bignerdranch.android.transitionexample.TransitionFragment">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="@string/hello_world" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="@string/hello_world" />

    <LinearLayout
        android:id="@+id/buttonContainer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <ImageView
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:src="@drawable/circle_red" />

        <Button
            android:id="@+id/goButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="goToScene1"
            android:text="@string/button_go" />

    </LinearLayout>

</LinearLayout>

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

容器XML布局

除了需要两个场景的布局之外,还需要一个容器布局装载场景。


<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <include layout="@layout/fragment_transition_scene_1"></include>
</FrameLayout>
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

需要为该容器设置一个id,以便在代码中使用。


activity逻辑实现

对照场景动画的实现流程图,可以编写如下代码,便能方便地实现场景动画。

public class MainActivity extends Activity {
    private Scene mScene1;
    private Scene mScene2;
    private AutoTransition autoTransition;
    private AutoTransition autoTransition2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_transition);

        //得到装载Scene场景的容器布局控件
        ViewGroup container = (ViewGroup) findViewById(R.id.container);
        //创建场景,设置场景的布局,并将场景装载到container中
        mScene1 = Scene.getSceneForLayout(container, R.layout.fragment_transition_scene_1, this);
        mScene2 = Scene.getSceneForLayout(container, R.layout.fragment_transition_scene_2, this);
        //设置场景动画
        autoTransition = new AutoTransition();
        autoTransition.setInterpolator(new EaseBackInInterpolator());
        autoTransition.setDuration(1000);

        autoTransition2 = new AutoTransition();
        autoTransition2.setInterpolator(new EaseQuadInInterpolator());
        autoTransition2.setDuration(500);

    }

    public void goToScene1(View view) {
        //执行场景动画
        TransitionManager.go(mScene1, autoTransition);
    }

    public void goToScene2(View view) {
        TransitionManager.go(mScene2, autoTransition2);
    }
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

补充 :用XML设置动画切换实现场景动画

前面使用代码的方式动态实现场景动画,下面将使用XML的方式实现场景动画,首先定义切换动画的XML。


场景切换动画


实现场景动画的动画效果主要是依靠抽象类Transition,它的实现类可以实现不同的动画效果。


abstract class Transition的实现类:

  • ChangeBounds (大小变化、位置变化)
  • ChangeClipBounds (改变剪切区域大小)
  • ChangeImageTransform (改变图形矩阵)
  • ChangeScroll (改变滚动方式)
  • ChangeTransform (改变转换方式)
  • TransitionSet (动画集合)
  • Visibility (可见性-元素的出现与消失) 
    –Explode (元素以爆炸方式出现或消失) 
    –Fade (元素淡入淡出) 
    –Slide (元素飞入飞出)

下面以动画集合TransitionSet为根标签设置一组动画。

<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
    android:transitionOrdering="sequential">
    <fade
        android:duration="1000"
        android:fadingMode="fade_out" />
    <changeBounds
        android:duration="2000"
        android:interpolator="@android:interpolator/bounce" />
    <fade
        android:duration="1000"
        android:fadingMode="fade_in" />
</transitionSet>
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

其中属性android:transitionOrdering=”sequential”表示按顺序执行动画。


同理,还可以继续定制其他动画效果。如下所示:

<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
    android:transitionOrdering="sequential">
    <fade
        android:duration="500"
        android:fadingMode="fade_out" />
    <changeBounds
        android:duration="800"      android:interpolator="@android:interpolator/anticipate_overshoot" />
    <fade
        android:duration="800"
        android:fadingMode="fade_in" />
</transitionSet>
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

上述动画执行效果为anticipate_overshoot样式。


设置完不同的动画样式集后,需要把这些集合装入到TransitionManager中,如下所示:

<transitionManager xmlns:android="http://schemas.android.com/apk/res/android">
    <transition
        android:fromScene="@layout/fragment_transition_scene_1"
        android:toScene="@layout/fragment_transition_scene_2"
        android:transition="@transition/fast_auto_transition" />
    <transition
        android:fromScene="@layout/fragment_transition_scene_2"
        android:toScene="@layout/fragment_transition_scene_1"
        android:transition="@transition/slow_auto_transition" />
</transitionManager>
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

activity逻辑实现


public class MainActivity extends Activity {
    private TransitionManager mTransitionManager;
    private Scene mScene1;
    private Scene mScene2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_transition);

        //得到装载Scene场景的容器布局控件
        ViewGroup container = (ViewGroup) findViewById(R.id.container);
        TransitionInflater transitionInflater = TransitionInflater.from(this);
        //创建TransitionManager对象,设置动画切换效果
        mTransitionManager = transitionInflater.inflateTransitionManager(R.transition.transition_manager, container);
        //创建场景,设置场景的布局,并将场景装载到container中
        mScene1 = Scene.getSceneForLayout(container, R.layout.fragment_transition_scene_1, this);
        mScene2 = Scene.getSceneForLayout(container, R.layout.fragment_transition_scene_2, this);
    }

    public void goToScene1(View view) {
        //执行场景动画
        mTransitionManager.transitionTo(mScene1); 
    }

    public void goToScene2(View view) {
        mTransitionManager.transitionTo(mScene2);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值