用SnackBar替換掉Toast?看完再決定
一、前言
Design Support Library 是 Google 發(fā)布的一個全新的兼容函數(shù)庫,它可以在 Android 2.1 (Api level 7)及以上的設(shè)備中,實現(xiàn) Material Design 的效果,這個函數(shù)庫同時也提供了一系列控件。
今天介紹的 SnackBar 就是其中之一。
在使用 Design Support Library 之前,需要在 build.gradle 文件中,添加依賴。
- compile 'com.android.support:design:25.3.0'
二、SnackBar 的常規(guī)使用
SnackBar 是一個輕量級的控件,它顯示在屏幕的底部,并且在顯示和隱藏的時候,帶有動畫效果。主要用于做一個快速的提示,它可以***的替代 Toast ,并且在使用的 API 上,也完全和 Toast 的使用方式類似,所以掌握起來,難度并不大。
它和 Toast ***的不同,是 SnackBar 可以帶有一個按鈕,也就是說它可以承載簡單的交互邏輯。
先來看看 SnackBar 能實現(xiàn)的效果。
可以看到,它會在底部顯示一個消息條,并且在顯示和隱藏的時候,都是自帶動畫的,可以承載一個TextView 和 Button。
SnackBar 的 API ,其實很多是參考了 Toast 的,所以他們的使用方式非常的相像。
就拿上面的例子中來看,代碼也非常的簡單。
SnackBar 之需要傳入一個 ViewGroup 然后它就可以在這個 ViewGroup 中顯示,通常我們會將這個 ViewGroup 置于屏幕的底部。
SnackBar 是沒有 public 的構(gòu)造方法的,所以需要使用 make() 方法,獲取到一個 SnackBar 對象,然后調(diào)用 show() 方法,即可顯示出來。
在上面的例子中,還使用 setAction() 方法,為其右邊的按鈕設(shè)定文字以及一個點擊事件。
下面介紹一下 SnackBar 自帶的一些基本 api:
make():構(gòu)造一個 SnackBar 對象,可進(jìn)行簡單配置。
show():用于顯示一個已經(jīng)構(gòu)造好的 SnackBar。
setText():為 SnackBar 的設(shè)置提示的消息內(nèi)容。
setAction():用于指定右邊的按鈕顯示的文字以及相應(yīng)的惦記事件。
setActionTextColor():設(shè)定右邊按鈕文字的顏色。
setCallback():設(shè)置 SnackBar 的顯示和隱藏時候的回掉監(jiān)聽。
setDuration():更新 Duration。
可以看到,SnackBar 本身只提供了非常簡單的 API 實現(xiàn),看來 Google 是指望開發(fā)者完全按照他們的風(fēng)格來設(shè)計 App。
三、帶著問題來看 SnackBar
前面已經(jīng)介紹了 SnackBar 的基本 API 的使用,如果想做其他的設(shè)置,就需要我們自己進(jìn)行一些操作了。那么接下來就讓我們帶著問題來看如何使用 SnackBar 。
下面會涉及到一些 SnackBar 的源碼,沒興趣的可以跳過直接看每個問題***的結(jié)論即可。
1、能不能設(shè)置一個常駐的 SnackBar
從上面的例子中可以看到,SnackBar 有點模仿 Toast 的意思,給出的兩個可供我們選擇的值,LENGTH_SHORT 、LENGTH_LONG ,分別表示兩個不同顯示時間的 SnackBar。
從代碼的文檔上看,貌似是沒有提供給我們用以設(shè)定常駐的 SnackBar 的方式。
但是細(xì)心看看源碼,可以發(fā)現(xiàn),duration,是通過 @Duration 接口限定輸入的,而 duration 實際上是有三個取值的,另外一個就是可以設(shè)置常駐的。
所以,如果我們有對 SnackBar 有常駐需求的話,可以使用 LENGTH_INDEFINITE 標(biāo)記即可。
2、去除掉滑動刪除功能
前面介紹過,SnackBar 是需要有一個 ViewGroup 容器來容納它的,而官方推薦使用 CoordinatorLayout 這個 ViewGroup,它實際上也是 Support Design Library 中提供的容器控件。
官方之所以推薦使用它,就是因為它可以讓用戶通過在 SnackBar 上進(jìn)行右滑操作,進(jìn)行刪除。
雖然說是這么說,我們還是從源碼中看看具體實現(xiàn)。
SnackBar 是繼承自 BaseTransientBottomBar 的,而這一段實現(xiàn)正是在父類中。
如圖所示,如果 SnackBar 的父布局是 CoordinatorLayout 的話,就使用 Behavior 來實現(xiàn)滑動刪除功能。
所以我們?nèi)绻恍枰瑒觿h除的功能,可以考慮用一個 FrameLayout 來容納 SnackBar。
或者需要滑動功能,卻發(fā)現(xiàn)沒有實現(xiàn),檢查一下布局,看承載 SnackBar 的容器,是不是 CoordinatorLayout。
3、禁用動畫能做到嗎?
不知道會不會有一些交互設(shè)計師要求不要動畫,就這么生硬的顯示出來。那么我們來看看到底動畫是不是可以被禁用掉。
執(zhí)行 SnackBar 顯示和隱藏動畫的邏輯,依然在它的父類BaseTransientBottomBar 中。查看源碼可以看到,它在執(zhí)行顯示和隱藏之前,都會調(diào)用 shouldAnimate() 方法,來判斷是否需要執(zhí)行一個動畫。
這么看,好像 SnackBar 是可以支持關(guān)閉動畫的,再看看 animateView 的實現(xiàn)。
是否使用動畫是依賴 AccessibilityManager 中的 enable 屬性決定的,而它是一個私有的屬性,并且沒有提供修改它的方法,并且如果用反射修改它的值,不確定會不會出現(xiàn)其他的問題,有待驗證。
那么可以簡單的認(rèn)為,SnackBar 的動畫,是無法簡單關(guān)閉的。
4、讓 SnackBar 顯示在頂部可以嗎?
既然 SnackBar 是有一個外部容器來承載它的,也就是說,容器在哪里,它實際上就出現(xiàn)在哪里。
所以如果將它置為頂部,其實是可以讓它在頂部出現(xiàn)的。但是你以為這樣就完了嗎?還需要考慮動畫的問題,雖然 SnackBar 會出現(xiàn)在頂部,但是動畫依然是從下到上出現(xiàn)的,你就會得到一個非常詭異的 SnackBar 。
這明顯不是我們想要的。那么是不是想辦法改變它出現(xiàn)和隱藏的動畫就可以了,繼續(xù)在源碼內(nèi)找答案。
animateViewIn() 方法就是 SnackBar 顯示時候調(diào)用的動畫,但是實際上,它無法被重寫。
所以,將 SnackBar 置于頂部,并且***的執(zhí)行動畫的設(shè)想是達(dá)不到的。
5、修改其他的UI樣式可以實現(xiàn)嗎?
SnackBar 原本提供的可以修改 UI 樣式的 API 非常的少,它只能修改右邊 Button 字體的顏色。
我們繼續(xù)在源碼內(nèi)找答案,看看源碼可以發(fā)現(xiàn),它的布局是在 SnackBar 中 inflater 出來的。布局文件為,design_layout_snackbar_include.xml
SnackBar 就是用一個 TextView 和一個 Button 實現(xiàn)的。也就是說,我們可以直接找到這兩個控件,來改變它的樣式。
參考 setText() 方法可以看到,實際上它是通過 mView 對象,拿到一個 SnackbarContentLayout 對象進(jìn)行操作。mView 這個 View 就是我們需要的。SnackBar 正好也提供了它的 get 方法,所以只需要拿到它,然后對其內(nèi)的 View 進(jìn)行樣式的修改,即可達(dá)到我們的需求。
所以,對于 SnackBar 的樣式修改,只要通過 getView() 拿到 mView 對象之后,就可以實現(xiàn)樣式的修改了。
四、題外話再說兩句
帶著問題看源碼是一個非常好的讀源碼的方式。實際上 SnackBar 用起來,看上去非常的好用,但是它封裝的東西太多了。如果我們親愛的設(shè)計師能遵照 Material Design 來設(shè)計 App,其實直接用 SnackBar 也是一個不錯的選擇。
對于一些定制要求的類似 SnackBar 的實現(xiàn)。實際上我們已經(jīng)把 SnackBar 的源碼讀了一遍了,關(guān)鍵點已經(jīng)掌握,自己參照 SnackBar 的源碼實現(xiàn)一套我們自己的 XxSnackBar 也并不難,都是自己寫的代碼了,如何實現(xiàn)就看我們自己的了。
我?guī)е膯栴},實際上也是我看到 SnackBar 會想到的問題。
【本文為51CTO專欄作者“張旸”的原創(chuàng)稿件,轉(zhuǎn)載請通過微信公眾號聯(lián)系作者獲取授權(quán)】