Android 5.0以后google推出了Material Design,Botton默許的觸摸反饋會有水波紋漣漪效果。而這類水波紋的效果實現(xiàn)主要依賴于RippleDrawable。
以下會介紹Ripple的基本使用及關(guān)于控制水波紋范圍的3種處理方法,僅作點明思路及學(xué)習(xí)筆記不作具體實現(xiàn)。
該效果通常以background的情勢顯現(xiàn),在XML中可以援用以下兩個系統(tǒng)自帶屬性:
- android:background=”?android:attr/selectableItemBackground” 有邊界波紋
- android:background=”?android:attr/··” 超越邊界波紋。該波紋由父布局繪制及限制邊界(API 21提供)
以selectableItemBackground
為例看下系統(tǒng)屬性的實現(xiàn)原理,發(fā)現(xiàn)該屬性的定義終究指向<item name="selectableItemBackground">@drawable/item_background_material</item>
,
查看該Drawable文件內(nèi)容為:
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlHighlight">
<item android:id="@id/mask">
<color android:color="@color/white" />
</item>
</ripple>
selectableItemBackgroundBorderless所對應(yīng)Drawable內(nèi)容為:
<ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="?attr/colorControlHighlight" />
特點:簡單,用于固定的view的處理,但靈活性不高。
目前網(wǎng)絡(luò)上的資料偏向于如何在xml的item下做文章,如在ripple中添加shape來限制范圍,驗證效果反而有各種小坑(誰驗誰知道)。卻不知官方早已提供解決方案。
根據(jù)官方對RippleDrawable的說明文檔,ripple的xml標(biāo)簽支持兩個屬性,分別是color
色調(diào)和radius
波紋半徑。故我們在使用時只需要新建ripple并以`android:background
的情勢調(diào)用便可.
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight"
android:radius="@dimen/ripple_radius" />
特點:可以動態(tài)控制,靈活性超級高,但對應(yīng)的處理復(fù)雜度和難度也較高。
設(shè)置水波紋點擊效果的本質(zhì)其實就是設(shè)置1個background,最為靈活的方法固然是自定義ripple,然后對目標(biāo)View直接setBackground便可.
RippleDrawable繼承于Drawable
java.lang.Object
? android.graphics.drawable.Drawable
? android.graphics.drawable.LayerDrawable
? android.graphics.drawable.RippleDrawable
自定義時可以繼承RippleDrawable也能夠直接繼承Drawable,二者的本質(zhì)分別是實現(xiàn)setRadius()
和實現(xiàn)setHotspotBounds()
,殊途同歸,都可以到達(dá)動態(tài)限制波紋大小的效果。系統(tǒng)的虛擬鍵NavigationBar就是使用的后者。
特點:簡單,靈活適中,易上手
以selectableItemBackgroundBorderless
超越邊界范圍為基礎(chǔ),以setHotspotBounds()
的方式動態(tài)控制其波紋范圍。
以下提供的是個簡易工具demo,調(diào)用時傳入對應(yīng)的viewxxx.setBackground(RippleUtils. getRippleDrawable(context, targetView))
,也能夠自己定義增加1個控制ripple范圍的方法:
/**
* Created by vito on 16⑴1⑴.
*/
public class RippleUtils {
private static RippleDrawable mRipple;
private static Drawable mTileBackground;
private static Drawable newTileBackground(Context context) {
final int[] attrs = new int[]{android.R.attr.selectableItemBackgroundBorderless};
final TypedArray ta = context.obtainStyledAttributes(attrs);
final Drawable d = ta.getDrawable(0);
ta.recycle();
return d;
}
private static void setRipple(RippleDrawable tileBackground, View v) {
mRipple = tileBackground;
updateRippleSize(v);
}
//以view的中心為圓心,寬的1/4為半徑的ripple范圍
private static void updateRippleSize(View v) {
// center the touch feedback on the center of the icon, and dial it down a bit
if (v.getWidth() != 0) {
final int cx = v.getWidth() / 2;
final int cy = v.getHeight() / 2;
final int rad = (int) (v.getWidth() * .25f);
Log.d("ripple", "updateRippleSize: rad=" + rad);
mRipple.setHotspotBounds(cx - rad, cy - rad, cx + rad, cy + rad);
} else {
// TODO: 17⑴⑼
}
}
//對外接口
public static RippleDrawable getRippleDrawable(Context context, View view) {
mTileBackground = newTileBackground(context);
if (mTileBackground instanceof RippleDrawable) {
setRipple((RippleDrawable) mTileBackground, view);
}
return mRipple;
}
}