沒時間解釋了,快使用Snackbar!——Android Snackbar花式使用指南

本文是在《Design Support Library第三部分:Snackbar樣式》《Snackbar使用及其注意事項》兩篇文章的啟發下而來,首先對兩篇文章的作者表示感謝。

Snackbar是Android Support Design Library庫中的一個控件,可以在屏幕底部快速彈出消息,比Toast更加好用。本文對原生Snackbar進行了修改,使其更加靈活。

1.Snackbar基本介紹

使用Snackbar要導入com.android.support:design庫。

Snackbar顯示在所有屏幕其它元素之上(屏幕最頂層),同一時間只能顯示一個snackbar。

Snackbar的基本使用很簡單,與Toast類似。

Snackbar.make(view, message_text, duration)
   .setAction(action_text, click_listener)
   .show();

make()方法是生成Snackbar的。Snackbar需要一個控件容器view用來容納,官方推薦使用CoordinatorLayout來確保Snackbar和其他組件的交互,比如滑動取消Snackbar、Snackbar出現時FloatingActionButton上移。顯示時間duration有三種類型LENGTH_SHORT、LENGTH_LONG和LENGTH_INDEFINITE。

setAction()方法可設置Snackbar右側按鈕,增加進行交互事件。如果不使用setAction()則只顯示左側message。

Snackbar.make(coordinatorLayout,"這是massage", Snackbar.LENGTH_LONG).setAction("這是action", new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Toast.makeText(MainActivity.this,"你點擊了action",Toast.LENGTH_SHORT).show();
     }
 }).show();

下面這張圖演示了上面代碼所實現的效果:Snackbar長顯示、點擊Action彈出toast提示以及Snackbar在CoordinatorLayout中滑動取消。

基礎演示.gif

如果你想在Snackbar的顯示時或消失時做些什么,可以調用Snackbar的setCallback()方法。

2.多彩Snackbar

Snackbar和Toast的默認樣式都很單一,但是有時我們希望把不同類型信息區別顯示,從而使用戶更容易注意到提示信息。所以使Snackbar變色是一個好主意。

Snackbar的官方API只提供了setActionTextColor()這個方法修改Action的文字顏色,這怎么辦?查源碼吧,哪里不會點哪里。(><)

在源碼中我們看到Snackbar中定義了一個繼承自LinearLayout的內部類SnackbarLayout,Snackbar的樣子就是由這個SnackbarLayout實現的。

SnackbarLayout中加載了R.layout.design_layout_snackbar_include布局文件,打開后看到下面這段代碼(我把padding、margin的具體數值也打了出來):

<merge xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
        android:id="@+id/snackbar_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:paddingTop="14dp"
        android:paddingBottom="14dp"
        android:paddingLeft="12dp"
        android:paddingRight="12dp"
        android:textAppearance="@style/TextAppearance.Design.Snackbar.Message"
        android:maxLines="2"
        android:layout_gravity="center_vertical|left|start"
        android:ellipsize="end"
        android:textAlignment="viewStart"/>

<Button
        android:id="@+id/snackbar_action"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="0dp"
        android:layout_marginStart="0dp"
        android:layout_gravity="center_vertical|right|end"
        android:paddingTop="14dp"
        android:paddingBottom="14dp"
        android:paddingLeft="12dp"
        android:paddingRight="12dp"
        android:visibility="gone"
        android:textColor="?attr/colorAccent"
        style="?attr/borderlessButtonStyle"/>
</merge>

由命名可知,以snackbar_text為名的TextView就是Snackbar左側的message。

好了,我們開始修改Snackbar的背景顏色和message字體顏色吧。

public static void setSnackbarColor(Snackbar snackbar, int messageColor, int backgroundColor) {
    View view = snackbar.getView();//獲取Snackbar的view
    if(view!=null){
        view.setBackgroundColor(backgroundColor);//修改view的背景色
        ((TextView) view.findViewById(R.id.snackbar_text)).setTextColor(messageColor);//獲取Snackbar的message控件,修改字體顏色
    }
}

很簡單,沒有幾行代碼。

本文最后提供的Snackbar封裝類代碼中定義了4種不同類型的信息:Info(妹子向你發來一條消息)、Confirm(妹子已收到你發出的消息)、Warning(妹子刪除了你發出的消息)、Alert(妹子已將你拉黑),分別用藍色、綠色、橙色、紅色來表示。

消息信息.png
警告和錯誤信息演示.gif

3.在Snackbar中增加圖標

短文本

通常 Snackbar 的高度應該僅僅用于容納所有的文本,而文本應該與執行的操作相關。Snackbar 中不能包含圖標,操作只能以文本的形式存在。

最多0-1個操作,不包含取消按鈕

當一個動作發生的時候,應當符合提示框和可用性規則。當有2個或者2個以上的操作出現時,應該使用提示框而不是 Snackbar,即使其中的一個是取消操作。如果 Snackbar 中提示的操作重要到需要打斷屏幕上正在進行的操作,那么理當使用提示框而非 Snackbar。

上面這段是谷歌 Material Design設計規范中的話。

但是我就是想在Snackbar中加圖標增加趣味性,引起用戶注意怎么辦?我就是想在Snackbar中放兩個按鈕進行可選非必要操作怎么辦?我就是想整幺蛾子。︿( ̄︶ ̄)︿

設計規范中的說法是有道理的,因為官方認為“Snackbar是一種針對操作的輕量級反饋機制”,做的麻煩了影響視覺感受。但是對于上述任性的開發者(或者是接了奇葩需求的苦逼開發者)我們也有解決方法。

前面我們提到過Snackbar的view是由SnackbarLayout實現的,而SnackbarLayout是繼承自LinearLayout,那么我們新建一個布局添加進去不就行了么。(~o ̄ ̄)~o...

public static void SnackbarAddView(Snackbar snackbar,int layoutId,int index) {
    View snackbarview = snackbar.getView();//獲取snackbar的View(其實就是SnackbarLayout)

    Snackbar.SnackbarLayout snackbarLayout=(Snackbar.SnackbarLayout)snackbarview;//將獲取的View轉換成SnackbarLayout

    View add_view = LayoutInflater.from(snackbarview.getContext()).inflate(layoutId,null);//加載布局文件新建View

    LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT);//設置新建布局參數

    p.gravity= Gravity.CENTER_VERTICAL;//設置新建布局在Snackbar內垂直居中顯示

    snackbarLayout.addView(add_view,index,p);//將新建布局添加進snackbarLayout相應位置
}

上面的代碼中,如果我們不設置向Snackbar中添加的布局文件的布局參數,新布局會顯示在Snackbar內的頂部。使用上述任性方法的時候要注意新加布局的大小和Snackbar內文字長度,Snackbar過大或過于花哨了可不好看。

下面是使用示例。我們先新建一個布局,暫時命名為snackbar_addview.xml,簡單的放進了一個ImageView,圖片就是android默認圖標。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
>
<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_vertical"
    android:src="@mipmap/ic_launcher"/>
</LinearLayout>

然后在activity中寫下snackbar的設置:

 Snackbar snackbar= Snackbar.make(coordinatorLayout,"這是massage", Snackbar.LENGTH_LONG);

 SnackbarUtil.setSnackbarColor(snackbar,SnackbarUtil.blue);

 SnackbarUtil.SnackbarAddView(snackbar,R.layout.snackbar_addview,0);

  snackbar.show();
添加圖標演示.gif

4.SnackbarUtil

我將我常用的Snackbar相關設置封裝成了一個類,大家可以根據自己的需求使用。

/**
 * Created by 趙晨璞 on 2016/5/1.
 */
public class SnackbarUtil {

public static final   int Info = 1;
public static final  int Confirm = 2;
public static final  int Warning = 3;
public static final  int Alert = 4;


public static  int red = 0xfff44336;
public static  int green = 0xff4caf50;
public static  int blue = 0xff2195f3;
public static  int orange = 0xffffc107;

/**
 * 短顯示Snackbar,自定義顏色
 * @param view
 * @param message
 * @param messageColor
 * @param backgroundColor
 * @return
 */
public static Snackbar ShortSnackbar(View view, String message, int messageColor, int backgroundColor){
    Snackbar snackbar = Snackbar.make(view,message, Snackbar.LENGTH_SHORT);
    setSnackbarColor(snackbar,messageColor,backgroundColor);
    return snackbar;
}

/**
 * 長顯示Snackbar,自定義顏色
 * @param view
 * @param message
 * @param messageColor
 * @param backgroundColor
 * @return
 */
public static Snackbar LongSnackbar(View view, String message, int messageColor, int backgroundColor){
    Snackbar snackbar = Snackbar.make(view,message, Snackbar.LENGTH_LONG);
    setSnackbarColor(snackbar,messageColor,backgroundColor);
    return snackbar;
}

/**
 * 自定義時常顯示Snackbar,自定義顏色
 * @param view
 * @param message
 * @param messageColor
 * @param backgroundColor
 * @return
 */
public static Snackbar IndefiniteSnackbar(View view, String message,int duration,int messageColor, int backgroundColor){
    Snackbar snackbar = Snackbar.make(view,message, Snackbar.LENGTH_INDEFINITE).setDuration(duration);
    setSnackbarColor(snackbar,messageColor,backgroundColor);
    return snackbar;
}

/**
 * 短顯示Snackbar,可選預設類型
 * @param view
 * @param message
 * @param type
 * @return
 */
public static Snackbar ShortSnackbar(View view, String message, int type){
    Snackbar snackbar = Snackbar.make(view,message, Snackbar.LENGTH_SHORT);
    switchType(snackbar,type);
    return snackbar;
}

/**
 * 長顯示Snackbar,可選預設類型
 * @param view
 * @param message
 * @param type
 * @return
 */
public static Snackbar LongSnackbar(View view, String message,int type){
    Snackbar snackbar = Snackbar.make(view,message, Snackbar.LENGTH_LONG);
    switchType(snackbar,type);
    return snackbar;
}

/**
 * 自定義時常顯示Snackbar,可選預設類型
 * @param view
 * @param message
 * @param type
 * @return
 */
public static Snackbar IndefiniteSnackbar(View view, String message,int duration,int type){
    Snackbar snackbar = Snackbar.make(view,message, Snackbar.LENGTH_INDEFINITE).setDuration(duration);
    switchType(snackbar,type);
    return snackbar;
}

//選擇預設類型
private static void switchType(Snackbar snackbar,int type){
    switch (type){
        case Info:
            setSnackbarColor(snackbar,blue);
            break;
        case Confirm:
            setSnackbarColor(snackbar,green);
            break;
        case Warning:
            setSnackbarColor(snackbar,orange);
            break;
        case Alert:
            setSnackbarColor(snackbar,Color.YELLOW,red);
            break;
    }
}

/**
 * 設置Snackbar背景顏色
 * @param snackbar
 * @param backgroundColor
 */
public static void setSnackbarColor(Snackbar snackbar, int backgroundColor) {
    View view = snackbar.getView();
    if(view!=null){
        view.setBackgroundColor(backgroundColor);
    }
}

/**
 * 設置Snackbar文字和背景顏色
 * @param snackbar
 * @param messageColor
 * @param backgroundColor
 */
public static void setSnackbarColor(Snackbar snackbar, int messageColor, int backgroundColor) {
    View view = snackbar.getView();
    if(view!=null){
        view.setBackgroundColor(backgroundColor);
        ((TextView) view.findViewById(R.id.snackbar_text)).setTextColor(messageColor);
    }
}

/**
 * 向Snackbar中添加view
 * @param snackbar
 * @param layoutId
 * @param index 新加布局在Snackbar中的位置
 */
public static void SnackbarAddView( Snackbar snackbar,int layoutId,int index) {
    View snackbarview = snackbar.getView();
    Snackbar.SnackbarLayout snackbarLayout=(Snackbar.SnackbarLayout)snackbarview;

    View add_view = LayoutInflater.from(snackbarview.getContext()).inflate(layoutId,null);

    LinearLayout.LayoutParams p = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT);
    p.gravity= Gravity.CENTER_VERTICAL;

    snackbarLayout.addView(add_view,index,p);
}

}

簡單的使用示例:

SnackbarUtil.ShortSnackbar(coordinator,"妹子向你發來一條消息",SnackbarUtil.Info).show();
消息演示.gif

整出幺蛾子的使用示例:

 Snackbar snackbar= SnackbarUtil.ShortSnackbar(coordinator,"妹子刪了你發出的消息",SnackbarUtil.Warning).setActionTextColor(Color.RED).setAction("再次發送", new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        SnackbarUtil.LongSnackbar(coordinator,"妹子已將你拉黑",SnackbarUtil.Alert).setActionTextColor(Color.WHITE).show();
    }
 });

 SnackbarUtil.SnackbarAddView(snackbar,R.layout.snackbar_addview,0);

 SnackbarUtil.SnackbarAddView(snackbar,R.layout.snackbar_addview2,2);

  snackbar.show();

這個示例中調用了兩次SnackbarAddView()方法向Snackbar中添加了兩個不同的自定義布局,效果如下(不建議大家這么玩 _(:з」∠)_ ):

添加多布局.gif

暫時就是這些。[]( ̄ ̄)*


關于Toast的花式使用請看我寫的Android Toast花式使用

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,002評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,400評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,136評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,714評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,452評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,818評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,812評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,997評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,552評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,292評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,510評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,721評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,121評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,429評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,235評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,480評論 2 379

推薦閱讀更多精彩內容