Ripple 水波紋效果


背景+波紋
對於有邊界限制的 Ripple ,我們就需要給他提供一個范圍,即添加一個item標簽。
  • 如果在一個ripple標簽中,添加一個item標簽,在item中添加如下屬性:
    • 【android:drawable="@color/***"】水波效果會限定在本身矩形區域內部
    • 【android:drawable="@drawable/png等"】水波效果會限定在圖片中非透明部分對應的區域內部
    • 【android:drawable="@color/shape"】水波效果會限定在shape對應的區域內部
  • 如果在一個ripple標簽中,添加一個item標簽,在item中添加一個selector標簽,那么將同時具有水波效果和selector效果

item帶不帶id的區別

添item時, 如果不指定id為@android:id/mask,那么不點擊時會顯示出該item指定的drawable
添item時,如果 指定id為@android:id/mask, 那么不點擊時 顯示出該item指定的drawable ,而僅僅在點擊的時候才出現
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#F00" >
    <item
        android:id="@android:id/mask"
        android:drawable="@drawable/ic_launcher"/>
</ripple>


實踐中發現,這兩個屬性都是一樣的,且和沒設置時的效果一樣
  • 【android:background="?android:attr/selectableItemBackground"】有邊界波紋
  • 【android:background="?android:attr/selectableItemBackgroundBorderless"】超出邊界波紋



當ripple標簽內只指定一個android:color屬性時,則該ripple效果的繪制會 溢出其所在View的邊界,直接繪制在父控件的背景之上。
如果父控件沒有設置背景,則會進一步繪制在父控件的上一級父控件的背景之上。

Ripple生效條件

當 View 有設置 OnClickListener 的情況下被點擊,或者獲得/失去焦點變化時,將出現Ripple效果
如果點擊效果沒有,很可能是該控件本身點擊沒開啟,設置如下屬性即可【android:clickable="true"】

不適用Ripple的場景

點擊之后就立馬消失的組件(setVisibility:gone invisible 或 remove)不適合使用
因為當組件恢復為visiable后,未播放完的Ripple動畫會繼續播放,會產生疑惑

硬件加速開關對無邊界Ripple的影響:

在Android 3.0 (API level 11)引入的硬件加速功能默認在application/Activity/View這三個層級上都是開啟的。
但如果手動關閉了,則無邊界Ripple不會生效。

子層(Child Layer)

由於View在不同的交互下有不同的state,常見的為pressed、focused或normal這三種狀態。
所以Ripple通過多個item來表示不同state下的顯示,每個item都是一個子層(Child Layer),能夠直接顯示color、shape、drawable/image 及 selector。
當Ripple存在一個或多個子層時,則ripple效果則被限定在當前View的邊界內了。無邊界效果(unbounded ripple)失效。

Mask層(Mask Layer)

可以設置指定子層item的android:id="@android:id/mask"來設定當前Ripple的Mask。
Mask的內容並不會被繪制到屏幕上,它的作用是限定Ripple效果的繪制區域。
mask所在的的子層限制了Ripple效果的最大范圍只能是View的邊界,不會擴散到父組件。

與ClickableSpan沖突

如果Layout有包含ClickableSpan的TextView,則發現該Layout設置Ripple的效果無法響應。
這個現象可以推斷出MotionEvent這個事件在TextView這一層級被消耗了,下一步應該為找出該事件為什么被消耗?
通過debug源碼,發現當點擊事件傳遞到TextView時,會進一步傳遞給LinkMovementMethod::onTouchEvent(),如果點擊位置處於ClickableSpan以外,則返回Touch.onTouchEvent(widget, buffer, event);
該方法在處理MotionEvent::ACTION_DOWN時默認返回true,導致Ripple失效。
那么解決思路也就簡單了,重寫LinkedMovementMethod::onTouchEvent()方法,當且僅當點擊到ClickableSpan時,才返回true即可。

布局

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:orientation="vertical" >
        <Button
            style="@style/textview"
            android:text="在5.0以上,Button默認自帶Ripple點擊效果" />
        <View style="@style/line" />
        <Button
            style="@style/textview"
            android:background="@drawable/ic_launcher"
            android:text="但是如果設置了其他的background \n Ripple點擊效果就沒了" />
        <View style="@style/line" />
        <TextView
            style="@style/textview"
            android:text="TextView默認是沒有Ripple點擊效果的" />
        <View style="@style/line" />
        <TextView
            style="@style/textview2"
            android:background="@drawable/_1_default"
            android:text="默認是圓形的、超出邊界的波紋\n波紋的直徑為控件寬高中的最大值" />
        <View style="@style/line" />
        <TextView
            style="@style/textview2"
            android:background="@drawable/_1_default2"
            android:text=" 但當波紋遇到其他控件的背景時,不會遮擋住其他控件的背景(比如不會擋住下面控件的背景)" />
        <View style="@style/line" />
        <TextView
            style="@style/textview"
            android:background="@drawable/_2_color_without_id"
            android:text="用顏色作為Mask,不指定id\n此時item中的顏色會被用來作為點擊前的背景顏色" />
        <View style="@style/line" />
        <TextView
            style="@style/textview"
            android:background="@drawable/_2_color_with_id"
            android:text="用顏色作為Mask,指定id\n此時item中的顏色沒任何卵用,但可以用來限定邊界" />
        <View style="@style/line" />
        <TextView
            style="@style/textview3"
            android:background="@drawable/_3_pic_without_id"
            android:text="用圖片作為Mask\n不指定id" />
        <View style="@style/line" />
        <TextView
            style="@style/textview3"
            android:background="@drawable/_3_pic_with_id"
            android:text="用圖片作為Mask\n指定id" />
        <View style="@style/line" />
        <TextView
            style="@style/textview3"
            android:background="@drawable/_4_shape_without_id"
            android:text="用shape作為Mask\n不指定id,矩形" />
        <View style="@style/line" />
        <TextView
            style="@style/textview3"
            android:background="@drawable/_4_shape_with_id"
            android:text="用shape作為Mask\n指定id,圓形" />
        <View style="@style/line" />
        <TextView
            style="@style/textview"
            android:background="@drawable/_5_selector_without_id"
            android:text="搭配selector使用,不指定id \n將同時具有水波效果和selector效果" />
        <View style="@style/line" />
        <TextView
            style="@style/textview"
            android:background="@drawable/_5_selector_with_id"
            android:text="搭配selector使用,指定id \n和上面的一樣,指定id后選擇器效果將丟失" />
        <View style="@style/line" />
        <TextView
            style="@style/textview"
            android:background="@drawable/_5_selector_fuza"
            android:text="這是一種負責的情況" />
    </LinearLayout>
</ScrollView>

樣式

<resources>
    <style name="textview">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">50dp</item>
        <item name="android:gravity">center</item>
        <item name="android:clickable">true</item>
    </style>
    <style name="textview2">
        <item name="android:layout_width">300dp</item>
        <item name="android:layout_height">50dp</item>
        <item name="android:gravity">center</item>
        <item name="android:clickable">true</item>
    </style>
    <style name="textview3">
        <item name="android:layout_width">120dp</item>
        <item name="android:layout_height">50dp</item>
        <item name="android:gravity">center</item>
        <item name="android:clickable">true</item>
    </style>
    <style name="line">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">1dp</item>
        <item name="android:background">#000</item>
    </style>
</resources>





附件列表

     


    免責聲明!

    本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



     
    粵ICP備18138465號   © 2018-2025 CODEPRJ.COM