自定義Snackbar-我們不一樣

為啥不一樣


最近做一個小項目馍资,項目中需要一個具備圓角背景的居中的提示筒主。這讓我想到了優(yōu)雅的Snackbar。但是Google了許多自定義Snackbar的帖子都不甚滿意鸟蟹,主要是在修改時不能很好的確定你想要的布局乌妙,大部分的文章都是通過獲取View,在代碼中修改例如背景建钥,文字顏色等藤韵,無法通過布局文件設置顯示的樣式。于是我設計了一個不一樣的實現(xiàn)熊经,實現(xiàn)并不復雜泽艘,只希望對看到此文的人有所幫助。

分析源碼

  • Snackbar的接口中沒有指定布局的接口镐依,我們只能從源碼分析是否有“漏洞“可尋匹涮。我們首先看一下make的源碼:


    SnackBar#make源碼

    如圖所示,我們看到了一個布局文件 “R.layout.design_layout_snackbar_include”槐壳,他對應著Snackbar的content然低。看到這里我們基本可以確定,這就是控制顯示樣式的布局文件雳攘。

  • 布局文件“ R.layout.design_layout_snackbar_include”:


    "內(nèi)容布局文件"

這個布局文件中一個SnackbarContentLayout包含一個Textview和一個Button带兜,這正是Snackbar 顯示時提示文字和按鈕。既然如此我們只要替換這個布局吨灭,我們就可以自定義布局了刚照。

修改布局代碼設計分析

  1. make 方法是一個靜態(tài)方法,通重寫是不可行的
  2. 然后我想到是否可以將舊的布局移除添加新的布局沃于?
    • 這種方式可以實現(xiàn)布局的修改涩咖,SnackBar中的內(nèi)容布局已經(jīng)變了;
    • 然后我們要考慮make時的文字內(nèi)容及button是否能應用到新的布局中去繁莹。我們在上一張圖中看到內(nèi)容布局是一個SnackbarContentLayout檩互。內(nèi)部有一個ID為snackbar_text的TextView和ID為snackbar_action的Button;我們的自定義布局中沒有這個ID咨演;而我們又想通過布局文件可視化的自定義布局我們該怎么辦呢闸昨?
  3. 使用布局文件自定義布局,并使得SnackbarContentLayout使用我們自定義的Msg view和Action button:
  • 我們無法再xml中指定id為support庫中的ID snackbar_text 和 snackbar_action薄风。那么我們退一步饵较,初始時我們用我們的ID,在Inflate布局后修改這個ID為相應的ID遭赂。這樣修改后我們在show時會出現(xiàn)問題:snackbar_text和snackbar_action對應的View是空的循诉。我們在看一下源碼:


    ”onFinishInflate“

源碼中看出,這兩個view在inflate完成后就不再find了撇他,不管是requesLayout還是invalid都不行茄猫。而且這個onFinishInflate是protected修飾的,無法重寫困肩。我們只能找其他方式划纽,于是我想到了反射,用反射調(diào)用onFinishInflate锌畸。至此我們的設計已經(jīng)完成

具體編碼實現(xiàn):

  • JSnackBar
class JSnackBar{
    private lateinit var snackbar: Snackbar
    private lateinit var msgView:TextView
    private lateinit var actBtn:Button
    fun make(view: View, msg:String, duration: Int, layout:Int):Snackbar{
            snackbar = Snackbar.make(view, msg, duration)
            val parent = snackbar.view as Snackbar.SnackbarLayout
            //Layout depend on your custon layout file
            parent.layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT
            parent.setBackgroundColor(Color.TRANSPARENT)
            parent.setPadding(0, 0,0, 0)
            val contentView = parent.getChildAt(0) as SnackbarContentLayout
            val newContentView = LayoutInflater.from(view.context).inflate(layout, contentView, false) as SnackbarContentLayout
            //Reset Id
            newContentView.id = contentView.id
            msgView = newContentView.findViewById(R.id.jepack_snack_bar_msg)
            actBtn  = newContentView.findViewById(R.id.jepack_snack_bar_action)

            msgView.id = android.support.design.R.id.snackbar_text
            actBtn.id = android.support.design.R.id.snackbar_action
            //Reflect find views勇劣。
            try {

                val method = newContentView::class.java.getDeclaredMethod("onFinishInflate")
                method.isAccessible = true
                method.invoke(newContentView)
                //Reset msg text
                msgView.text = msg
                val index = parent.indexOfChild(contentView)
                //替換布局
                parent.removeViewAt(index)
                parent.addView(newContentView, index)
            }catch (e:Exception){
                LogUtil.e("Failed to change snackbar layout! ", e.message)
            }
            return snackbar
        }
}
  • 布局文件(這只是我的一個簡單實現(xiàn),可根據(jù)實際情況自定義)
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.internal.SnackbarContentLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_gravity="bottom"
    android:padding="<padding>">
    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@id/jepack_snack_bar_msg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:singleLine="true"
            android:ellipsize="end"
            android:textColor="@android:color/white"
            android:layout_gravity="center_horizontal"
            android:background="@drawable/shape_tip_bg"
            android:paddingStart="@dimen/snack_padding"
            android:paddingEnd="@dimen/snack_padding"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            />
        <Button
            android:id="@id/jepack_snack_bar_action"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:button="@null"
            android:visibility="gone"
            />

    </android.support.constraint.ConstraintLayout>
</android.support.design.internal.SnackbarContentLayout>

這里面的圖片潭枣,dimen等需要你根據(jù)需求修改比默;

  • ids設置,方便擴展
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <item type="id" name="jepack_snack_bar_msg" />
    <item type="id" name="jepack_snack_bar_action" />
</resources>

到此我們就可以輕松實現(xiàn)了我們需要的效果卸耘。

“效果圖”

此代碼將增加到Github倉庫中, 歡迎指正退敦!

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蚣抗,隨后出現(xiàn)的幾起案子侈百,更是在濱河造成了極大的恐慌瓮下,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钝域,死亡現(xiàn)場離奇詭異讽坏,居然都是意外死亡,警方通過查閱死者的電腦和手機例证,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門路呜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人织咧,你說我怎么就攤上這事胀葱。” “怎么了笙蒙?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵抵屿,是天一觀的道長。 經(jīng)常有香客問我捅位,道長轧葛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任艇搀,我火速辦了婚禮尿扯,結果婚禮上,老公的妹妹穿的比我還像新娘焰雕。我一直安慰自己衷笋,他們只是感情好,可當我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布矩屁。 她就那樣靜靜地躺著右莱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪档插。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天亚再,我揣著相機與錄音郭膛,去河邊找鬼。 笑死氛悬,一個胖子當著我的面吹牛则剃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播如捅,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼棍现,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了镜遣?” 一聲冷哼從身側(cè)響起己肮,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后谎僻,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體娄柳,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年艘绍,在試婚紗的時候發(fā)現(xiàn)自己被綠了赤拒。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡诱鞠,死狀恐怖挎挖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情航夺,我是刑警寧澤蕉朵,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站敷存,受9級特大地震影響墓造,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜锚烦,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一觅闽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧涮俄,春花似錦蛉拙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至苞尝,卻和暖如春畸肆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背宙址。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工轴脐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人抡砂。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓大咱,卻偏偏與公主長得像,于是被迫代替她去往敵國和親注益。 傳聞我的和親對象是個殘疾皇子碴巾,可洞房花燭夜當晚...
    茶點故事閱讀 45,055評論 2 355

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

  • 1、通過CocoaPods安裝項目名稱項目信息 AFNetworking網(wǎng)絡請求組件 FMDB本地數(shù)據(jù)庫組件 SD...
    陽明先生_X自主閱讀 15,982評論 3 119
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,180評論 25 707
  • 2016年送給自己的最后一份禮物 CZT#23 CZTAsia#1木木帶領大家禪繞畫深度游丑搔,用31天時間厦瓢,送給自己...
    木之慧閱讀 404評論 0 2
  • 當我摔倒在地提揍,沒有人來拉我一把,也沒有人上前抱起我旷痕,從我身邊走過無數(shù)的人碳锈,他們都是好人都是善良的人,他們鼓勵我站起...
    清溪淺淺流閱讀 335評論 0 0