Android 5.X 新特性详解(四)Material Design动画效果

Material Design 动画效果

动画已经成为了UI设计中一个非常重要的组成部分,在Android 5.X的UI设计Material Design中,更是使用了大量的动画效果,同时Google也在官方文档上增加了对动画的设计指导。

Ripple效果

在Android 5.X中,Material Design 大量使用了Ripple效果,即点击后的波纹效果。可以通过如下代码设置波纹的背景。

//波纹有边界
android:background="?android:attr/selectableItemBackground"
//波纹超出边界
android:background="?android:attr/selectableItemBackgroundBorderless"

波纹有边界是指波纹被限制在控件的边界中,而波纹超出边界则是波纹不会限制在控件边界中,会呈圆形发散出去。波纹效果示例XML代码如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:background="@android:color/holo_blue_bright">

    <Button
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:textColor="@android:color/white"
        android:background="?android:attr/selectableItemBackground"
        android:text="有界波纹" />

    <Button
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:background="?android:attr/selectableItemBackgroundBorderless"
        android:textColor="@android:color/white"
        android:text="无界波纹" />

</LinearLayout>

这里写图片描述

同样可以在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:colorPrimary" />
        </shape>
    </item>
</ripple>

使用方法如下所示,与使用一般的XMl资源方法相同。

<Button
  android:layout_width="100dp"
  android:layout_height="100dp"
  android:background="@drawable/ripple"

Circular Reveal

Circular Reveal具体表现为一个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——动画开始半径
  • endRadius——动画结束半径

示例代码如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/oval"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:background="@mipmap/ic_launcher"/>

    <ImageView
        android:id="@+id/rect"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:background="@mipmap/ic_launcher"/>
</LinearLayout>

程序代码如下:

public class CircularActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_circular);
        final View oval = findViewById(R.id.oval);
        oval.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                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 = findViewById(R.id.rect);
        rect.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //Math.hypot方法获取直角三角形斜边的长度
                Animator animator = ViewAnimationUtils.createCircularReveal(rect,
                        0, 0, 0, (float) Math.hypot(rect.getWidth(), rect.getHeight()));
                animator.setInterpolator(new AccelerateDecelerateInterpolator());
                animator.setDuration(2000);
                animator.start();
            }
        });
    }
}

以上程序设置了两种形式,通过设置不同的坐标值,改变圆形展开的方式和效果。

这里写图片描述

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" />

同样,在代码中也可以调用AnimatorInflater.loadStateListAnimator()方法,并且通过View.setStateListAnimator()方法分配动画到视图上。

  • animated-selector

animated-selector同样是一个状态改变的动画效果Selector。在Android 5.0 中,很多Material Design 的控件设计,都是通过这种方式来实现,例如我们熟悉的check_box的动画效果,就是使用类似帧动画的切换效果,模拟进行点击时的切换效果。

下面就来实现一个具有动画效果的状态切换按钮,首先需要一组状态切换图,如下图所示:

这里写图片描述

有了这样一组图,就可以在XML文件中定义animated-selector。animated-selector与selector的使用十分类似,同样是通过item标签来区分不同的状态。图ic_done_anim_000与图ic_plus_anim_030分别代表两种不同的状态。同时也给这两种状态增加了ID来进行区分,并使用transition标签来给这两种状态设置不同的过渡图片,这点非常类似Android中的帧动画效果,完整代码如下所示。

<?xml version="1.0" encoding="utf-8"?>
<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_000" />
    </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_004" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_plus_anim_005" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_plus_anim_006" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_plus_anim_007" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_plus_anim_008" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_plus_anim_009" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_plus_anim_010" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_plus_anim_011" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_plus_anim_012" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_plus_anim_013" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_plus_anim_014" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_plus_anim_015" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_plus_anim_016" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_plus_anim_017" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_plus_anim_018" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_plus_anim_019" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_plus_anim_020" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_plus_anim_021" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_plus_anim_022" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_plus_anim_023" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_plus_anim_024" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_plus_anim_025" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_plus_anim_026" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_plus_anim_027" />
            </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_004" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_done_anim_005" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_done_anim_006" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_done_anim_007" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_done_anim_008" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_done_anim_009" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_done_anim_010" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_done_anim_011" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_done_anim_012" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_done_anim_013" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_done_anim_014" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_done_anim_015" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_done_anim_016" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_done_anim_017" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_done_anim_018" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_done_anim_019" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_done_anim_020" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_done_anim_021" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_done_anim_022" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_done_anim_023" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_done_anim_024" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_done_anim_025" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_done_anim_026" />
            </item>
            <item android:duration="16">
                <bitmap android:src="@drawable/ic_done_anim_027" />
            </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中,通常使用系统属性来设置切换状态。

public class ViewStateActivity extends Activity {

    private boolean mIsCheck;
    private ImageView mImageView;
    private static final int[] STATE_CHECKED = new int[]{android.R.attr.state_checked};
    private static final int[] STATE_UNCHECKED = new int[]{};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_view_state);
        //view state changes animation
        Button button = (Button) findViewById(R.id.button);
        StateListAnimator animator = AnimatorInflater.loadStateListAnimator(this, R.drawable.anim_change);
        button.setStateListAnimator(animator);

        //animated-selector
        mImageView = (ImageView) findViewById(R.id.image);
    }

    public void anim(View view) {
        if(mIsCheck){
            mImageView.setImageState(STATE_UNCHECKED, true);
            mIsCheck = false;
        }else{
            mImageView.setImageState(STATE_CHECKED, true);
            mIsCheck = true;
        }
    }

}

程序运行效果如下所示:

这里写图片描述

代码下载

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值