Material Design 之 Touch Feedback

目录

概要

在 Materil Design(一下简称 MD ) 中,当用户与 UI 交互的时候,触摸反馈(Touch Feedback)可以在交互点提供一种及时的视觉确认效果。

设置触摸反馈

Button 在 MD 中默认就有一个反馈动画,使用的是 RippleDrawable 类,这个类很有意思,它根据手指与 UI 交互的不同状态(例如,长按,短按,抬起)转化为不同的波纹效果(Ripple Effect)。 这个效果就不演示了,相信大家已经都看烂了。

然而,并不是所有的控件都有默认的触摸反馈的波纹效果,例如 TextView,那么,怎么给这些控件添加触摸反馈的波纹效果呢?

可以使用系统提供的两个属性来在 XML 中给 View 设置背景,也就是 android:background

  • ?android:attr/selectableItemBackground 提供了有边界的波纹效果
  • ?android:attr/selectableItemBackgroundBorderless 提供了无边界的波纹效果

selectableItemBackgroundBorderless 在 API 21 才可用。

在 RelativeLayout 中添加一个 TextView 并居中显示

    <TextView
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_centerInParent="true"
        android:clickable="true"
        android:gravity="center"
        android:text="设置触摸反馈效果"/>

TextView 的属性,我特意设置了一个可点击的属性 android:clickable,这样才能响应点击事件,后面才能看到波纹效果。

在 Android Studio 中效果如下

这里写图片描述

扫描二维码关注公众号,回复: 8622611 查看本文章

TextView 默认是没有边界的,当我们点击 TextView 后,发现并没有任何触摸反馈的效果(即使设置了可点击啊属性)。

那么,按照前面说的,给 TextView 设置一个触摸反馈的背景属性,例如,先设置了一个有边界的波纹属性

    <TextView
        android:background="?android:attr/selectableItemBackground"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_centerInParent="true"
        android:clickable="true"
        android:gravity="center"
        android:text="设置触摸反馈效果"/>

当点击 TextView 后,效果如下

这里写图片描述

可以看到两个效果
1.会以触摸点为中心,形成一个波纹效果
2.TextView 显示出了边界

有些时候,我们需要 TextView 响应点击事件,但是并不需要 TextView 显示边界。例如,在微博中,点击一个用户的名字,会跳转到用户相关的页面,如果在点击名字的时候,出现了边界,是不是有点丑陋? 反正我觉得有点丑的。

那么,如果我们既想有点击波纹效果,又不想出现边界,就可以用系统提供的无边界波纹效果

    <TextView
        android:background="?android:attr/selectableItemBackgroundBorderless"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_centerInParent="true"
        android:clickable="true"
        android:gravity="center"
        android:text="设置触摸反馈效果"/>

当点击 TextView 的时候,你只会看到一个波纹效果,而并没有出现边界,如下图所示。

这里写图片描述

系统波纹的颜色是一个淡灰色,我们可以换换

    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="colorControlHighlight">@color/colorAccent</item>
    </style>

这里写图片描述

RippleDrawable

系统提供的波纹效果,是一个灰色的波纹效果,那么如果我们想自定义的波纹的颜色呢?

前面提到过,Button 默认的触摸反馈效果,是用 RippleDrawable 类实现的,可以在 XML 中定义一个 Ripple Drawable。

res/drawable/ripple.xml

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="@color/colorPrimary">
</ripple>

我给这个 RippleDrawable 定义了一个颜色 android:color="@color/colorPrimary",这就是波纹的颜色。

现在把这个 Ripple Drawale 设置为 TextView 背景

    <TextView
        android:background="@drawable/ripple"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_centerInParent="true"
        android:clickable="true"
        android:gravity="center"
        android:text="设置触摸反馈效果"/>

点击 TextView 效果如下

这里写图片描述

由于用的是模拟器,因此这个波纹不是很明显,如果在真机上,可以明显看到一个波纹效果,而这个波纹颜色,就是刚才设置。

那么,现在长按下,可以看到如下效果

这里写图片描述

ok,这个长按效果不纠结了,知道这么回事就行了。

那么现在有一个问题,怎样才能像 Button 的波纹效果一样,大小限制在整个 Button 内呢?

RippleDrawable 是继承自 LayerDrawable,所以可以加一层 layer,来限制波纹的大小。

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="@color/colorPrimary">
    <item android:drawable="@android:color/white"/>
</ripple>

再点击 TextView 后,会有如下效果

这里写图片描述

看懂这个效果后,可能有人会问了,刚才你不是说到给 TextView 设置有带边框的波纹很丑吗? 是的,确实丑。

然而在开发中,我们还可能遇到一种情况,例如 CardView 本身也是没有触摸反馈效果的,但是它有边界,如果在 CardView 上添加这个有边界的波纹,这样就不丑了吧?具体效果,就留给大家自己去试试了。

其实 RippleDrawable 还有一个很有意思的事情,它又一个遮罩层,id 为 android.R.id.mask,既然叫做遮罩层,那就是限制波纹的范围了。
刚才看到有界的波纹的范围其实就是 TextView 的大小范围,那么可以用遮罩层来改变这个范围的形状,如果大家清楚图像混合的几种模式,这就很好理解了。

首先为 RippleDrawable 加一个 layer,用来定义遮罩层

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="@color/colorPrimary">

    <item android:drawable="@android:color/white"/>

    <item
        android:id="@android:id/mask"
        android:drawable="@drawable/ripple_mask"/>
</ripple>

注意,遮罩层的 id 一定要定义为 @android:id/mask

再看看 res/ripple_mask.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="oval">
    <solid android:color="@android:color/holo_red_light"/>
</shape>

形状定义为了 oval,系统会自动根据 TextView 的大小来决定是圆形还是椭圆。

如果按照图像混合原理来看,其实这里的颜色的透明度只要是不透明的,就能形成遮罩效果,但是从我测试的来看,这里的颜色可以随意设置,也不需要关心透明度。

当我们点击 TextView 的时候,就与无边界的波纹效果一样,只是这个波纹的圆小一点,如下图

这里写图片描述

刚才说了,到底是椭圆还是圆是根据 TextView 的大小而定的,如果把 TextView 的高度改下

    <TextView
        android:background="@drawable/ripple"
        android:layout_width="200dp"
        android:layout_height="100dp"
        android:layout_centerInParent="true"
        android:clickable="true"
        android:gravity="center"
        android:text="@string/button"/>

现在 TextView 是长方形了,那么再点击的时候,效果如下

这里写图片描述

现在就是一个椭圆的波纹效果了,是不是很有点意思。

再回到了 res/ripple_mask.xml,刚才我们说到,颜色其实是可以随意定义的,那么我们还要设置这个干嘛? 当然是为了形成 GradientDrawable 对象了。

这里用的是填充的方式来形成 GradientDrawable 对象,当然,我们也可以用描边的方式

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="oval">
    <stroke
        android:width="10dp"
        android:color="@android:color/black"/>
</shape>

那么点击 TextView ,效果如下

这里写图片描述

这就有点意思了!

参考链接

https://developer.android.com/training/material/animations.html#Touch
https://developer.android.com/reference/android/graphics/drawable/RippleDrawable.html

发布了44 篇原创文章 · 获赞 30 · 访问量 400万+

猜你喜欢

转载自blog.csdn.net/zwlove5280/article/details/78297947