参考文献:

ipple Effect / Touch Feedback / 触摸反馈动画

1. 简介

材料设计中的触摸反馈在用户和 UI 元素交互的点提供瞬时视觉确认。例如,当按钮被触摸时显示一个水波纹效果。 这是 Android 5.0 默认的触摸反馈动画。水波纹动画通过新的 RippleDrawable 类实现。水波纹效果可以配置在 View 边界的末端或超出 View 的边界。例如,下面的图片序列说明了在一个按钮上触摸时的水波纹效果动画:

rippleanim.png

刚开始在按钮上触摸时会出现左边第一张图片所示,剩下的图片说明了水波纹效果是怎样扩散到按钮边界的。 当水波纹动画完成,View 恢复到初始状态。默认的水波纹动画不超过一秒,但可以自定义动画的长度。

注意水波纹效果只会在 Android 5.0 及以上显示,之前的版本会高亮显示。

2. 系统自带的两个 Ripple 波纹效果

xml 实现

//有边界, 就是如上效果
?android:attr/selectableItemBackground
//无边界 (要求API21以上), 波纹可以超过 width 和 height 的限制
?android:attr/selectableItemBackgroundBorderless

使用时只需要把上面这两个值作为 View 的 android:background=""android:foreground="" 即可(如果已经有背景, 可以设置到前景属性中)。同时如果想要效果显示出来要保证 View 是可点击的(比如控件本身可点击、或者给控件设置点击事件、 或给控件设置 android:clickable="true")。

<Button
    android:id="@+id/button"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:background="?attr/selectableItemBackgroundBorderless" />

这里的颜色是系统默认的,可以在 theme 里更改默认的波纹颜色

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- API 21 theme customizations can go here. -->
    <item name="android:colorControlHighlight">#ff0000</item>
</style>

java 实现

int[] attrs = new int[]{R.attr.selectableItemBackground};
TypedArray typedArray = getActivity().obtainStyledAttributes(attrs);
int backgroundResource = typedArray.getResourceId(0, 0);
mView.setBackgroundResource(backgroundResource);

3. 自定义 Ripple

3.1 无边界

ripple 说是触摸反馈动画,其实它就是一个 Drawable,所以定义时需要放到 drawable 文件夹下:``

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="#4285f4">
</ripple>
  • 上面中 ripple 属性中 color 代表的是波纹的颜色。
  • ripple 中还有一个属性为 radius (波纹大小),则触摸显示的波纹为设置的固定大小,不会为手指触摸点开始显示。
  • 边界的颜色如果没有透明度,为纯色的话,会遮盖其它无边界的波纹。具体效果可以查看 Demo。

3.2 有边界

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="#4285f4"><!--波纹点击颜色-->
    <!-- 添加边界 -->
    <item android:drawable="@color/blue"/>
</ripple>
  • 上面的 item 是为了设置一个边界,其实它的作用就是为 View 绘制一个默认的背景。并且如果有更复杂的 需求,可以直接在 <item><shape/></item> 中绘制一个 shape 。

4. Button 的触摸反馈

Button 在 v21 以上默认情况下是自带有 ripple 效果和点击Z轴抬高的阴影效果(会在视图状态动画中详解)的。
但是如果你给 Button 设置了背景图,上面自带的默认点击效果都会失去。这时如果想保持点击效果有下面几种方式:

方式一

把 Button 的背景设置放到 Theme 中更改

<style name="AutoButton" parent="AppTheme">
    <item name="buttonStyle">@style/Widget.AppCompat.Button</item>
    <item name="colorButtonNormal">?attr/colorAccent</item>
</style>

然后把这个 theme 设置给 Button,其中 clolorButtonNormal 就是默认状态下的背景(无需再设置 background )。这样就会保持按钮默认的点击效果。

方式二

给 Button 设置普通背景的同时,设置 Ripple 效果给 Foreground 前景属性

方式三

自定义 ripple

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#FF0000" >
    <item>
        <selector>
            <item
                android:drawable="@drawable/icon_bg1"
                android:state_pressed="true">
            </item>
            <item
                android:drawable="@drawable/icon_bg2"
                android:state_pressed="false">
            </item>
        </selector>
    </item>
</ripple>

也就相当于把 Ripple 和 Shape 结合在一起。

另外需要注意的是,在自定义 <ripple/> 时,我们一般把它放到 drawable-v21 文件夹下, 在 drawable 文件夹下放置兼容低版本的普通 Drawable 文件,如 <shape/> 或者 <selector/>