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 中效果如下
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 ,效果如下
這就有點意思了!