hello钻洒,大家好,上一篇介紹了drawable如何顯示到view上锄开,基本上是以background
屬性來(lái)講的素标,其實(shí)在view中用到的drawable地方還是挺多的,還不屬性drawable顯示到view的流程萍悴,可以看下我寫(xiě)的上一篇android中drawable顯示到view上的過(guò)程头遭,今天要介紹的也是跟drawable一個(gè)相關(guān)的屬性foreground
屬性,不過(guò)該屬性之前只是針對(duì)FrameLayout的癣诱,后來(lái)在23的api之后所有的view都能用該屬性计维,因此大家知道這么回事就行了,而且在后面view源碼中也會(huì)看到該屬性兼容的代碼撕予,該屬性一般在開(kāi)發(fā)中能實(shí)現(xiàn)水波點(diǎn)擊的效果鲫惶,不知道大家平時(shí)用得多不多,好了实抡,下面還是跟往常一樣剑按,通過(guò)一個(gè)簡(jiǎn)單的例子來(lái)介紹該屬性的使用:
<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="我是測(cè)試的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="我是測(cè)試的view" />
demo是很簡(jiǎn)單疾就,為了演示效果,上面textview的foreground屬性是一個(gè)顏色值艺蝴,下面textview的foreground是獲取應(yīng)用的style里面的
selectableItemBackground
屬性猬腰。第一個(gè)textview的foreground屬性顏色直接把background屬性覆蓋掉了,而第二個(gè)textview的foreground是一個(gè)波紋效果猜敢,因此帶著這些問(wèn)題順著源碼看下這些問(wèn)題姑荷,直接看獲取view的foreground屬性地方:
在此處看到該屬性值在api>=23或view是frameLayout的時(shí)候調(diào)用了
setForeground
方法,該方法其實(shí)跟setBackground
方法做的是類(lèi)似的事缩擂,先是判斷有沒(méi)有foreground鼠冕,如果有先銷(xiāo)毀掉foreground,然后調(diào)用applyForegroundTint
方法設(shè)置foreground的著色情況胯盯,最后也是觸發(fā)了重新繪制view懈费。那直接看view繪制的時(shí)候,是怎么繪制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方法幾個(gè)關(guān)鍵方法給列出來(lái)了博脑,先是繪制background憎乙,然后是onDraw,最后才是foreground叉趣,所以說(shuō)在上面第一個(gè)例子中泞边,因?yàn)樽詈蟛爬L制foreground,因此顯示的結(jié)果只有foreground的顏色了疗杉,下面來(lái)看看onDrawForeground
方法是怎么繪制foreground的:
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();
//根據(jù)mForegroundInfo.mGravity得到foreground的bounds
Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(),
foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld);
foreground.setBounds(overlayBounds);
}
foreground.draw(canvas);
}
}
其實(shí)跟background的繪制差不多阵谚,只不過(guò)在foreground設(shè)置bounds的時(shí)候,多了一個(gè)foreground.gravity的判斷烟具,意思是foreground的權(quán)重梢什,但是我測(cè)試過(guò)權(quán)重只有fill的情況下才起作用,其他的其中foreground.gravity都會(huì)讓foreground的顏色失去作用朝聋。
寫(xiě)到這的時(shí)候绳矩,大家知道了事例一中為什么加了foreground屬性顏色值之后,為什么設(shè)置textview的background以及text屬性都看不到了吧玖翅,因?yàn)閒oreground是在繪制之后最后繪制的翼馆,所以被foreground的顏色給覆蓋了。那第二個(gè)事例中為什么會(huì)有點(diǎn)擊的波紋效果呢金度,這個(gè)就需要了解?attr/selectableItemBackground
代表的是啥应媚,這個(gè)其實(shí)是跟咱們的主題style屬性相關(guān),也就是順著app的application的style屬性可以找到該屬性是什么:
直接來(lái)到21下面的
Base.Theme.AppCompat.Light
下面找:
此處找到了關(guān)于
selectableItemBackground
屬性猜极,但還是style里面的屬性中姜,不要緊,咱們繼續(xù)找父style,最后在Theme.Material.Light
style下面找到了:
也就是說(shuō)水波效果用到的資源文件是
item_background_material
的drawable文件丢胚,繼續(xù)看下該資源文件是怎么定義的:
<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下面定義的:
繼續(xù)看下
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>
此處定義了一個(gè)透明度為0.12携龟,顏色為黑色的selector顏色值兔跌。在上一節(jié)我們知道drawable的子類(lèi)是根據(jù)子類(lèi)的各種標(biāo)簽生成不同的drawable,而水波的資源文件是ripple
標(biāo)簽峡蟋,所以從這里可以知道實(shí)質(zhì)是一個(gè)RippleDrawable
坟桅,關(guān)于RippleDrawable
后面再講解它們?cè)趺蠢L制的。下面我們嘗試下改變水波效果的顏色蕊蝗,按照系統(tǒng)自帶的這個(gè)水波效果來(lái)寫(xiě)寫(xiě)仅乓,定義了一個(gè)change.xml的drawable文件:
<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>
可以看到這里引用了一個(gè)ripple_color
的文件:
<?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>
用到了一個(gè)透明度為0.5,并且顏色用的是系統(tǒng)生成的顏色值蓬戚。最后在view上引用change.xml
文件:
效果大家可以錄制的gif:
好了關(guān)于水波效果就說(shuō)到這里夸楣,后面主要說(shuō)說(shuō)StateListDrawable、RippleDrawable實(shí)現(xiàn)效果的繪制是怎么來(lái)的子漩,以及介紹drawable相關(guān)的api是如何使用的豫喧,以及使用drawable下面其他的不常用的drawable來(lái)實(shí)現(xiàn)好玩的功能。