Material Design动画(三)

本文介绍3个MaterialDesign动画中的触摸反馈特效demo,包括用ripple标签实现点击涟漪波纹反馈,点击元素产生吸附效果,及综合运用实现元素躲闪等交互特效。

本文将介绍3个关于Material Design动画中触摸反馈特效的demo。


demo1:用ripple标签实现点击屏幕后的涟漪波纹反馈特效


效果展示

当点击屏幕时,屏幕上将出现以手指为圆心、向外扩散的圆形涟漪波纹效果,如下所示:


涟漪效果1涟漪效果2


实现过程


上述特效是Material Design特有的效果,故需要使用Android5.0自带的主题,若不考虑兼容性,可以在AndroidManifest中声明的主题继承于如下父类主题:

parent="android:Theme.Material.Light"
 
  • 1
  • 1

考虑到Android碎片化问题,更多时候,还是应使用兼容主题作为父类主题:

parent="android:theme.AppCompat.Light"
 
  • 1
  • 1

下面是界面的布局,就是两个简单的TextView,涟漪波纹效果就在这两个TextView上产生。


<RelativeLayout 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: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=".MainActivity">

    <TextView

        android:id="@+id/image"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:background="@drawable/myripple"
        android:clickable="true"
        android:gravity="center"
        android:text="Clickable" />

    <TextView
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_below="@id/image"
        android:layout_marginTop="20dp"
        android:background="@drawable/myripple2"
        android:clickable="true"
        android:gravity="center"
        android:text="Clickable" />

</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
  • 32
  • 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

代码的关键就是属性android:background,Android5.0为开发者提供了一个标签ripple,只需在drawable文件夹下创建一个以ripple为根标签的XML文件,就能产生波纹涟漪效果:


ripple.xml文件

<ripple

    xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#ff0099ff">


</ripple>
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

ripple2.xml文件

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#349856">
    <item android:drawable="@android:color/holo_red_light"></item>

</ripple>
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

ripple标签中的android:color属性是必须要指定的,该属性用于指定元素被点击时的颜色;若还需指定未点击时的元素颜色,需要加入子标签item,并通过android:drawable属性指定未点击元素时的颜色,此时,波纹只能在控件所在区域扩散(如点击第二个TextView时所示),而若需要在点击元素时,波纹能扩散至元素范围之外(如点击第一个TextView时所示),只需要把子标签item去掉就可以了,此时的元素背景色将是缺省色。


demo2:点击元素产生元素被手指吸附的效果


效果展示


当点击某个元素时,元素在Z轴上增加了一定的高度(通过增加阴影表现),仿佛是元素被按下的手指吸附一样,效果如下:


未点击无吸附效果 
未点击时无吸附效果


点击时有吸附效果 
点击时有吸附效果


实现过程

布局如下:


<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#EAEAEA">

    <android.support.v7.widget.Toolbar
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?android:colorPrimary"
        android:elevation="5dp"
        android:minHeight="?attr/actionBarSize" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="@dimen/activity_horizontal_margin"
        android:layout_marginRight="@dimen/activity_horizontal_margin"
        android:orientation="vertical">

        <android.support.v7.widget.CardView
            android:layout_width="100dp"
            android:layout_height="45dp"
            android:layout_gravity="center"
            android:layout_marginTop="16dp"
            android:clickable="true"
            android:elevation="2dp"
            android:stateListAnimator="@drawable/translation_selector"
            card_view:cardCornerRadius="4dp" />

        <android.support.v7.widget.CardView
            android:layout_width="100dp"
            android:layout_height="45dp"
            android:layout_gravity="center"
            android:layout_marginTop="16dp"
            android:clickable="true"
            android:elevation="2dp"
            android:stateListAnimator="@drawable/translation_selector"
            card_view:cardCornerRadius="4dp" />

        <android.support.v7.widget.CardView
            android:layout_width="100dp"
            android:layout_height="45dp"
            android:layout_gravity="center"
            android:layout_marginBottom="@dimen/activity_vertical_margin"
            android:layout_marginTop="16dp"
            android:clickable="true"
            android:elevation="2dp"
            android:stateListAnimator="@drawable/translation_selector"
            card_view:cardCornerRadius="4dp" />

    </LinearLayout>
</FrameLayout>
 
  • 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
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 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
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

首先定义了1个ToolBar和3个CardView,这两个控件都在android.support.v7.widget包中,故声明控件时需要指定全限定类名;重点是属性android:stateListAnimator,该属性可为元素设置“基于状态的动画(stated-based animator)”,通过在drawable文件夹中定制以selector为根标签的XML文件,可实现吸附效果。


在drawable中自定义基于状态的动画:


<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <set>
            <objectAnimator android:duration="@android:integer/config_shortAnimTime" android:propertyName="translationZ" android:valueTo="10dp" android:valueType="floatType" />
        </set>
    </item>
    <item android:state_pressed="false">
        <set>
            <objectAnimator android:duration="100" android:propertyName="translationZ" android:valueTo="2dp" android:valueType="floatType" />
        </set>
    </item>
</selector>

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

Android5.0为selector增加了动画效果,上述代码分别指定了当元素处于点击状态和非点击状态时的属性,可以看出,是通过属性动画实现的,关键就在于属性android:valueTo,该属性指定元素在Z轴上的高度。


demo3:综合

本demo将综合上面两个demo的部分知识点,实现当元素处于点击状态时,该元素发生躲闪的小游戏。


实现效果


初始样式 
初始样式


点击1 
点击第一行第二列的元素时,元素上移。


点击2 
点击第二行第二列的元素时,元素消失。


点击3 
点击第三行第一列的元素时,元素向左下角移动。


实现过程

定义一个元素的统一样式,方便代码复用。


<style name="touchboard">
        <item name="android:layout_margin">10dp</item>
        <item name="android:layout_gravity">center</item>
        <item name="android:layout_width">80dp</item>
        <item name="android:layout_height">80dp</item>
        <item name="android:elevation">2dp</item>
        <item name="android:clickable">true</item>
        <item name="android:gravity">center</item>
        <item name="android:background">#ffffff</item>
    </style>
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

接着定义布局文件,代码的关键仍然是属性android:stateListAnimator,通过该属性可以定制基于状态的动画。

<RelativeLayout 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: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=".MainActivity">


    <TextView
        android:id="@+id/center"
        style="@style/touchboard"
        android:layout_centerInParent="true"
        android:stateListAnimator="@drawable/tocenter" />

    <TextView
        android:id="@+id/up"
        style="@style/touchboard"
        android:layout_above="@id/center"
        android:layout_centerHorizontal="true"
        android:stateListAnimator="@drawable/toup" />

    <TextView
        android:id="@+id/down"
        style="@style/touchboard"
        android:layout_below="@id/center"
        android:layout_centerHorizontal="true"
        android:stateListAnimator="@drawable/todown"

        />

    <TextView
        android:id="@+id/left"
        style="@style/touchboard"
        android:layout_centerVertical="true"
        android:layout_toLeftOf="@id/center"
        android:stateListAnimator="@drawable/toleft" />

    <TextView
        android:id="@+id/right"
        style="@style/touchboard"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@id/center"
        android:stateListAnimator="@drawable/toright" />

    <TextView
        android:id="@+id/rightup"
        style="@style/touchboard"
        android:layout_above="@id/center"
        android:layout_toRightOf="@id/center"
        android:stateListAnimator="@drawable/toupright" />

    <TextView
        android:id="@+id/leftup"
        style="@style/touchboard"
        android:layout_above="@id/center"
        android:layout_toLeftOf="@id/center"
        android:stateListAnimator="@drawable/toupleft" />

    <TextView
        android:id="@+id/rightdown"
        style="@style/touchboard"
        android:layout_below="@id/center"
        android:layout_toRightOf="@id/center"
        android:stateListAnimator="@drawable/torightdown" />

    <TextView
        android:id="@+id/leftdown"
        style="@style/touchboard"
        android:layout_below="@id/center"
        android:layout_toLeftOf="@id/center"
        android:background="#ffffffff"
        android:stateListAnimator="@drawable/todownleft" />


</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
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 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
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79

在drawable文件夹中用selector标签给元素定制基于状态的动画:


给第一行第一列元素指定动画:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <set>
            <objectAnimator android:propertyName="translationY"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="-80dp"
                android:valueType="floatType"/>
            <objectAnimator android:propertyName="translationX"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="-80dp"
                android:valueType="floatType"/>
        </set>
    </item>
    <item
        android:state_pressed="false"
        >
        <set>
            <objectAnimator android:propertyName="translationY"
                android:duration="100"
                android:valueTo="0dp"
                android:valueType="floatType"/>
            <objectAnimator android:propertyName="translationX"
                android:duration="100"
                android:valueTo="0dp"
                android:valueType="floatType"/>
        </set>
    </item>
</selector>

 
  • 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
  • 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

给第一行第二列元素指定动画:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <set>
            <objectAnimator android:propertyName="translationY"
                android:duration="@android:integer/config_shortAnimTime"
                android:interpolator="@android:interpolator/fast_out_slow_in"
                android:valueTo="-80dp"
                android:valueType="floatType"/>

        </set>
    </item>
    <item
        android:state_pressed="false"
        >
        <set>
            <objectAnimator android:propertyName="translationY"
                android:duration="100"
                android:valueTo="0dp"
                android:valueType="floatType"/>

        </set>
    </item>
</selector>

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

给第二行第二列元素指定动画:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <set>
            <objectAnimator android:duration="@android:integer/config_shortAnimTime"

                android:propertyName="ScaleX"

                android:valueTo="0" android:valueType="floatType" />
            <objectAnimator android:duration="@android:integer/config_shortAnimTime"

                android:propertyName="ScaleY"

                android:valueTo="0" android:valueType="floatType" />
        </set>
    </item>
    <item android:state_pressed="false">
        <set>
            <objectAnimator android:duration="100" android:propertyName="ScaleX" android:valueTo="1" android:valueType="floatType" />
            <objectAnimator android:duration="@android:integer/config_shortAnimTime"

                android:propertyName="ScaleY"

                android:valueTo="1" android:valueType="floatType" />
        </set>
    </item>
</selector>

 
  • 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
  • 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

给第三行第三列指定动画:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <set>
            <objectAnimator android:propertyName="translationY"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="80dp"
                android:valueType="floatType"/>
            <objectAnimator android:propertyName="translationX"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="80dp"
                android:valueType="floatType"/>
        </set>
    </item>
    <item
        android:state_pressed="false"
        >
        <set>
            <objectAnimator android:propertyName="translationY"
                android:duration="100"
                android:valueTo="0dp"
                android:valueType="floatType"/>
            <objectAnimator android:propertyName="translationX"
                android:duration="100"
                android:valueTo="0dp"
                android:valueType="floatType"/>
        </set>
    </item>
</selector>

 
  • 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
  • 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

上面代码实现了部分元素的动画效果,其余动画效果与之相仿,它们的共同特点是分别设置了元素被点击和未被点击时的动画效果,而元素移动的方向主要用属性android:propertyName来设置,若为值为"translationY",则表示元素在纵向上有位移;若为"translationX",则表示元素在横向上有位移;若为"ScaleX""ScaleY",表示元素自身在横轴或纵轴上有伸缩。而屏幕规定的坐标轴是以左上角为原点,水平向右的方向是X轴的正方向,铅直向下的方向是Y轴的正方向。通过这个规定,就可以通过属性android:valueTo来确定元素运动的方向和距离:元素向左移动80dp,可将属性android:propertyName设为"translationX",属性android:valueTo设为设为”-80dp”;元素向右下方移动80dp,可以同事指定两个属性动画,其中一个属性android:propertyName设为"translationX",属性android:valueTo设为设为”80dp”,另一个属性android:propertyName设为"translationY",属性android:valueTo设为设为”80dp”,若希望元素被点击时消失,可指定两个属性动画,其中一个为android:propertyName="ScaleX" android:valueTo="0",另一个为android:propertyName="ScaleY" android:valueTo="0"

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值