android中foreground水波實(shí)現(xiàn)過(guò)程分析

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" />

simple

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屬性地方:

image

在此處看到該屬性值在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屬性可以找到該屬性是什么:

image

直接來(lái)到21下面的Base.Theme.AppCompat.Light下面找:

image

此處找到了關(guān)于selectableItemBackground屬性猜极,但還是style里面的屬性中姜,不要緊,咱們繼續(xù)找父style,最后在Theme.Material.Lightstyle下面找到了:

image

也就是說(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.Lightstyle下面定義的:

image

繼續(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文件:

image

效果大家可以錄制的gif:

image

好了關(guān)于水波效果就說(shuō)到這里夸楣,后面主要說(shuō)說(shuō)StateListDrawable、RippleDrawable實(shí)現(xiàn)效果的繪制是怎么來(lái)的子漩,以及介紹drawable相關(guān)的api是如何使用的豫喧,以及使用drawable下面其他的不常用的drawable來(lái)實(shí)現(xiàn)好玩的功能。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末痛单,一起剝皮案震驚了整個(gè)濱河市嘿棘,隨后出現(xiàn)的幾起案子劲腿,更是在濱河造成了極大的恐慌旭绒,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件焦人,死亡現(xiàn)場(chǎng)離奇詭異挥吵,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)花椭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)忽匈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人矿辽,你說(shuō)我怎么就攤上這事丹允。” “怎么了袋倔?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵雕蔽,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我宾娜,道長(zhǎng)批狐,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任前塔,我火速辦了婚禮嚣艇,結(jié)果婚禮上承冰,老公的妹妹穿的比我還像新娘。我一直安慰自己食零,他們只是感情好困乒,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著慌洪,像睡著了一般顶燕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上冈爹,一...
    開(kāi)封第一講書(shū)人閱讀 52,262評(píng)論 1 308
  • 那天涌攻,我揣著相機(jī)與錄音,去河邊找鬼频伤。 笑死恳谎,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的憋肖。 我是一名探鬼主播因痛,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼岸更!你這毒婦竟也來(lái)了鸵膏?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤怎炊,失蹤者是張志新(化名)和其女友劉穎谭企,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體评肆,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡债查,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瓜挽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盹廷。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖久橙,靈堂內(nèi)的尸體忽然破棺而出俄占,到底是詐尸還是另有隱情,我是刑警寧澤淆衷,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布缸榄,位于F島的核電站,受9級(jí)特大地震影響吭敢,放射性物質(zhì)發(fā)生泄漏碰凶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望欲低。 院中可真熱鬧辕宏,春花似錦、人聲如沸砾莱。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)腊瑟。三九已至聚假,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間闰非,已是汗流浹背膘格。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留财松,地道東北人瘪贱。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像辆毡,于是被迫代替她去往敵國(guó)和親菜秦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容