hello,你們好,上一篇介紹了drawable如何顯示到view上,基本上是以background
屬性來說的,其實在view中用到的drawable地方仍是挺多的,還不屬性drawable顯示到view的流程,能夠看下我寫的上一篇android中drawable顯示到view上的過程,今天要介紹的也是跟drawable一個相關的屬性foreground
屬性,不過該屬性以前只是針對FrameLayout的,後來在23的api以後全部的view都能用該屬性,所以你們知道這麼回事就好了,並且在後面view源碼中也會看到該屬性兼容的代碼,該屬性通常在開發中能實現水波點擊的效果,不知道你們平時用得多很少,好了,下面仍是跟往常同樣,經過一個簡單的例子來介紹該屬性的使用:android
<TextView
android:id="@+id/view"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginTop="50dp"
android:background="#cccccc"
android:foreground="#ff0000"
android:gravity="center"
android:text="我是測試的view" />
<TextView
android:id="@+id/view1"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginTop="50dp"
android:background="#cccccc"
android:foreground="?attr/selectableItemBackground"
android:gravity="center"
android:text="我是測試的view" />
複製代碼
selectableItemBackground
屬性。第一個textview的foreground屬性顏色直接把background屬性覆蓋掉了,而第二個textview的foreground是一個波紋效果,所以帶着這些問題順着源碼看下這些問題,直接看獲取view的foreground屬性地方:
setForeground
方法,該方法其實跟
setBackground
方法作的是相似的事,先是判斷有沒有foreground,若是有先銷燬掉foreground,而後調用
applyForegroundTint
方法設置foreground的着色狀況,最後也是觸發了從新繪製view。那直接看view繪製的時候,是怎麼繪製foreground的:
public void draw(Canvas canvas) {
final int privateFlags = mPrivateFlags;
final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
(mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
if (!dirtyOpaque) {
drawBackground(canvas);
}
if (!dirtyOpaque) onDraw(canvas);
onDrawForeground(canvas);
}
複製代碼
這裏我把draw方法幾個關鍵方法給列出來了,先是繪製background,而後是onDraw,最後纔是foreground,因此說在上面第一個例子中,由於最後才繪製foreground,所以顯示的結果只有foreground的顏色了,下面來看看onDrawForeground
方法是怎麼繪製foreground的:canvas
public void onDrawForeground(Canvas canvas) {
onDrawScrollIndicators(canvas);
onDrawScrollBars(canvas);
final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null;
if (foreground != null) {
if (mForegroundInfo.mBoundsChanged) {
mForegroundInfo.mBoundsChanged = false;
final Rect selfBounds = mForegroundInfo.mSelfBounds;
final Rect overlayBounds = mForegroundInfo.mOverlayBounds;
if (mForegroundInfo.mInsidePadding) {
selfBounds.set(0, 0, getWidth(), getHeight());
} else {
selfBounds.set(getPaddingLeft(), getPaddingTop(),
getWidth() - getPaddingRight(), getHeight() - getPaddingBottom());
}
final int ld = getLayoutDirection();
//根據mForegroundInfo.mGravity獲得foreground的bounds
Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(),
foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld);
foreground.setBounds(overlayBounds);
}
foreground.draw(canvas);
}
}
複製代碼
其實跟background的繪製差很少,只不過在foreground設置bounds的時候,多了一個foreground.gravity的判斷,意思是foreground的權重,可是我測試過權重只有fill的狀況下才起做用,其餘的其中foreground.gravity都會讓foreground的顏色失去做用。api
寫到這的時候,你們知道了事例一中爲何加了foreground屬性顏色值以後,爲何設置textview的background以及text屬性都看不到了吧,由於foreground是在繪製以後最後繪製的,因此被foreground的顏色給覆蓋了。那第二個事例中爲何會有點擊的波紋效果呢,這個就須要瞭解?attr/selectableItemBackground
表明的是啥,這個實際上是跟我們的主題style屬性相關,也就是順着app的application的style屬性能夠找到該屬性是什麼:bash
Base.Theme.AppCompat.Light
下面找:
selectableItemBackground
屬性,但仍是style裏面的屬性,沒關係,我們繼續找父style,最後在
Theme.Material.Light
style下面找到了:
item_background_material
的drawable文件,繼續看下該資源文件是怎麼定義的:
<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>
複製代碼
color顏色用的是?attr/colorControlHighlight
,我們能夠看下該屬性是怎麼定義的,該屬性也是在Theme.Material.Light
style下面定義的:app
ripple_material_light
是怎麼定義的:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:alpha="@dimen/highlight_alpha_material_light"
android:color="@color/foreground_material_light" />
</selector>
複製代碼
此處定義了一個透明度爲0.12,顏色爲黑色的selector顏色值。在上一節咱們知道drawable的子類是根據子類的各類標籤生成不一樣的drawable,而水波的資源文件是ripple
標籤,因此從這裏能夠知道實質是一個RippleDrawable
,關於RippleDrawable
後面再講解它們怎麼繪製的。下面咱們嘗試下改變水波效果的顏色,按照系統自帶的這個水波效果來寫寫,定義了一個change.xml的drawable文件:ide
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@drawable/ripple_color">
<item android:id="@android:id/mask">
<color android:color="@android:color/white" />
</item>
</ripple>
複製代碼
能夠看到這裏引用了一個ripple_color
的文件:post
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:alpha="0.5" android:color="@color/colorPrimary" />
</selector>
複製代碼
用到了一個透明度爲0.5,而且顏色用的是系統生成的顏色值。最後在view上引用change.xml
文件:測試
好了關於水波效果就說到這裏,後面主要說說StateListDrawable、RippleDrawable實現效果的繪製是怎麼來的,以及介紹drawable相關的api是如何使用的,以及使用drawable下面其餘的不經常使用的drawable來實現好玩的功能。spa