12.8 Material Design动画效果" class="reference-link">12.8 Material Design动画效果
动画已经成了UI设计中一个非常重要的组成部分,在Android 5.X的UI设计Material Design中,更是使用了大量的动画效果,同时Google也在官方设计文档上增加了对动画的设计指导。
12.8.1 Ripple效果" class="reference-link">12.8.1 Ripple效果
在Android 5.X中,Material Design大量使用了Ripple效果,即点击后的波纹效果。可以通过如下代码设置波纹的背景。
- //波纹有边界
- android:background="?android:attr/selectableItemBackground"
- //波纹超出边界
- android:background="?android:attr/selectableItemBackgroundBorderless"
波纹有边界是指波纹被限制在控件的边界中,而波纹超出边界则是波纹不会限制在控件边界中,会呈圆形发散出去,下面通过一个实例,演示一下Android 5.X的波纹效果,XML代码如下所示。
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/holo_blue_bright">
- <Button
- android:layout_width="100dp"
- android:layout_height="100dp"
- android:background="?android:attr/selectableItemBackground"
- android:text="有界波纹"
- android:textColor="@android:color/white" />
- <Button
- android:layout_width="100dp"
- android:layout_height="100dp"
- android:background="?android:attr/selectableItemBackground-Borderless"
- android:textColor="@android:color/white"
- android:text="无界波纹" />
- </LinearLayout>
显示效果如图12.19、图12.20所示。
![]() | ![]() |
| 图12.19 波纹效果1 | 图12.20 波纹效果2 |
同样,你也可以在XML文件中直接来创建一个具有Ripple效果的XML文件,代码如下所示。
- <ripple
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="@android:color/holo_blue_bright">
- <item>
- <shape
- android:shape="oval">
- <solid android:color="?android:colorAccent" />
- </shape>
- </item>
- </ripple>
使用方法如下所示,与使用一般的XML资源方法相同。
- <Button
- android:layout_width="100dp"
- android:layout_height="100dp"
- android:background="@drawable/ripple" />
显示效果如图12.21所示。
图12.21 波纹效果</h4>
12.8.2 Circular Reveal" class="reference-link">12.8.2 Circular Reveal
这个动画效果在Google IO大会的演示视频中出现了很多次,具体表现为一个View以圆形的形式展开、揭示出来。通过ViewAnimationUtils.createCircularReveal()方法可以创建一个RevealAnimator动画,代码如下所示。
- public static Animator createCircularReveal(
- View view,
- int centerX,
- int centerY,
- float startRadius,
- float endRadius) {
- return new RevealAnimator(view, centerX, centerY, startRadius, endRadius);
- }
RevealAnimator的使用非常简单,主要是设置几个关键的坐标点:
- centerX动画开始的中心点X
- centerY动画开始的中心点Y
- startRadius动画开始半径
- startRadius动画结束半径
通过下面的例子,可以非常直观地感受到这种动画效果,XML代码如下所示。
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- tools:context=".MainActivity">
- <ImageView
- android:id="@+id/oval"
- android:layout_width="100dp"
- android:layout_height="100dp"
- android:background="@drawable/oval" />
- < ImageView
- android:id="@+id/rect"
- android:layout_width="100dp"
- android:layout_height="100dp"
- android:background="@drawable/rect" />
- </LinearLayout>
程序代码如下所示。
- package com.xys.myapplication;
- import android.animation.Animator;
- import android.app.Activity;
- import android.os.Bundle;
- import android.view.View;
- import android.view.ViewAnimationUtils;
- import android.view.animation.AccelerateDecelerateInterpolator;
- import android.view.animation.AccelerateInterpolator;
- import com.imooc.myapplication.R;
- public class MainActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- final View oval = this.findViewById(R.id.oval);
- oval.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- Animator animator =
- ViewAnimationUtils.createCircularReveal(
- oval,
- oval.getWidth() / 2,
- oval.getHeight() / 2,
- oval.getWidth(),
- 0);
- animator.setInterpolator(
- new AccelerateDecelerateInterpolator());
- animator.setDuration(2000);
- animator.start();
- }
- });
- final View rect = this.findViewById(R.id.rect);
- rect.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- Animator animator =
- ViewAnimationUtils.createCircularReveal(
- rect,
- 0,
- 0,
- 0,
- (float) Math.hypot(rect.getWidth(),
- rect.getHeight()));
- animator.setInterpolator(
- new AccelerateInterpolator());
- animator.setDuration(2000);
- animator.start();
- }
- });
- }
- }
以上程序设置了两种形式,通过设置不同的坐标值,改变圆形展开的方式和效果,如图12.22、图12.23所示。
![]() | ![]() |
| 图12.22 CircularReveal(中心) | 图12.23 CircularReveal(边界) |
12.8.3 View state changes Animation" class="reference-link">12.8.3 View state changes Animation
在Android 5.X中,系统提供了视图状态改变来设置一个视图的状态切换动画。
- StateListAnimator
StateListAnimator作为视图改变时的动画效果,通常会使用Selector来进行设置,但以前设置Selector的时候,通常是修改背景来达到反馈的效果。现在,在Android 5.X中,可以使用动画来作为视图改变的效果。
在XML中定义一个StateListAnimator,并添加到Selector中,代码如下所示。
- <?xml version="1.0" encoding="utf-8"?>
- <selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true">
- <set>
- <objectAnimator android:propertyName="rotationX"
- android:duration="@android:integer/config_shortAnimTime"
- android:valueTo="360"
- android:valueType="floatType"/>
- </set>
- </item>
- <item android:state_pressed="false">
- <set>
- <objectAnimator android:propertyName="rotationX"
- android:duration="@android:integer/config_shortAnimTime"
- android:valueTo="0"
- android:valueType="floatType"/>
- </set>
- </item>
- </selector>
在一般的XML布局中,使用如下代码来将StateListAnimator添加给一个视图。
- <Button
- android:layout_width="200dp"
- android:layout_height="200dp"
- android:stateListAnimator="@drawable/anim_change"/>
同样,在代码中也可以调用AnimationInflater.loadStateListAnimator()方法,并且通过View.setStateListAnimator()方法分配动画到视图上,效果如图12.24所示。
图12.24 StateListAnimator
- animated-selector
animated-selector同样是一个状态改变的动画效果Selector。在Android 5.0中,很多Material Design的控件设计,都是通过这种方式来实现的,例如我们熟悉的check_box的动画效果,就是使用类似帧动画的切换效果,模拟进行点击时的切换效果,如图12.25所示。
图12.25 check_box状态切换图
下面就仿照这个例子来实现一个具有动画效果的状态切换按钮。首先需要一组类似图12.25的状态切换图,如图12.26所示。
图12.26 状态切换图
有了这样一组图,就可以在XML文件中定义animated-selector。animated- selector与selector的使用十分类似,同样是通过<item>标签来区分不同的状态,代码如下所示。
- <item
- android:id="@+id/state_on"
- android:state_checked="true">
- <bitmap android:src="@drawable/ic_done_anim_000" />
- </item>
- <item android:id="@+id/state_off">
- <bitmap android:src="@drawable/ic_plus_anim_030" />
- </item>
图ic_done_anim_000与图ic_plus_anim_030分别代表两种不同的状态。同时,我们也给这两种状态增加了ID来进行区分,下面就可以使用<transition>标签来给这两种状态设置不同的过渡图片,这点非常类似Android中的帧动画效果,完整代码如下所示。
- <animated-selector xmlns:android="http://schemas.android.com/apk/
- res/android">
- <item
- android:id="@+id/state_on"
- android:state_checked="true">
- <bitmap android:src="@drawable/ic_done_anim_030" />
- </item>
- <item android:id="@+id/state_off">
- <bitmap android:src="@drawable/ic_plus_anim_030" />
- </item>
- <transition
- android:fromId="@+id/state_on"
- android:toId="@+id/state_off">
- <animation-list>
- <item android:duration="16">
- <bitmap android:src="@drawable/ic_plus_anim_000" />
- </item>
- <item android:duration="16">
- <bitmap android:src="@drawable/ic_plus_anim_001" />
- </item>
- <item android:duration="16">
- <bitmap android:src="@drawable/ic_plus_anim_002" />
- </item>
- <item android:duration="16">
- <bitmap android:src="@drawable/ic_plus_anim_003" />
- </item>
- ……
- <item android:duration="16">
- <bitmap android:src="@drawable/ic_plus_anim_028" />
- </item>
- <item android:duration="16">
- <bitmap android:src="@drawable/ic_plus_anim_029" />
- </item>
- <item android:duration="16">
- <bitmap android:src="@drawable/ic_plus_anim_030" />
- </item>
- </animation-list>
- </transition>
- <transition
- android:fromId="@+id/state_off"
- android:toId="@+id/state_on">
- <animation-list>
- <item android:duration="16">
- <bitmap android:src="@drawable/ic_done_anim_000" />
- </item>
- <item android:duration="16">
- <bitmap android:src="@drawable/ic_done_anim_001" />
- </item>
- <item android:duration="16">
- <bitmap android:src="@drawable/ic_done_anim_002" />
- </item>
- <item android:duration="16">
- <bitmap android:src="@drawable/ic_done_anim_003" />
- </item>
- ……
- <item android:duration="16">
- <bitmap android:src="@drawable/ic_done_anim_028" />
- </item>
- <item android:duration="16">
- <bitmap android:src="@drawable/ic_done_anim_029" />
- </item>
- <item android:duration="16">
- <bitmap android:src="@drawable/ic_done_anim_030" />
- </item>
- </animation-list>
- </transition>
- </animated-selector>
有了animated-selector之后,只需要把它应用到一个ImageView上即可。同时,在代码中设置不同的点击状态。在Android中,通常使用如下所示的系统属性来设置切换状态。
- private static final int[] STATE_CHECKED = new int[]{
- android.R.attr.state_checked};
- private static final int[] STATE_UNCHECKED = new int[]{};
当点击时,通过setImageState方法来改变一个背景状态图,完整代码如下所示。
- package com.imooc.animatedselector;
- import android.app.Activity;
- import android.graphics.drawable.Drawable;
- import android.os.Bundle;
- import android.view.View;
- import android.widget.ImageView;
- public class MainActivity extends Activity {
- private boolean mIsCheck;
- private static final int[] STATE_CHECKED = new int[]{
- android.R.attr.state_checked};
- private static final int[] STATE_UNCHECKED = new int[]{};
- private ImageView mImageView;
- private Drawable mDrawable;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- mImageView = (ImageView) findViewById(R.id.image);
- mDrawable = getResources().getDrawable(
- R.drawable.fab_anim);
- mImageView.setImageDrawable(mDrawable);
- }
- public void anim(View view) {
- if (mIsCheck) {
- mImageView.setImageState(STATE_UNCHECKED, true);
- mIsCheck = false;
- } else {
- mImageView.setImageState(STATE_CHECKED, true);
- mIsCheck = true;
- }
- }
- }
程序运行效果如图12.27所示,初始状态时,按钮显示“+”。而当点击时,按钮显示“√”,同时具有一个切换效果,而不是直接从“+”变为“√”,如图12.28所示。
![]() | ![]() |
| 图12.27 初始状态 | 图12.28 点击状态 |
