您的位置:首页 > Web前端

Material Design 之 Touch Feedback

2017-10-20 17:44 246 查看

目录

目录
概要

设置触摸反馈

RippleDrawable

参考链接

概要

在 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 中效果如下



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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息