此文章是我在簡書的文章,自行搬到開源中國.簡書地址:SnackbarUtils:一行代碼搞定Snackbarjava
Snackbar在Android中的使用日益普遍,很大程度上替代了傳統的Toast,相比Toast擁有更好的使用體驗.android
但在咱們的APP中,不少時候用到Snackbar,都須要對Snackbar的樣式及顯示效果進行一些定製以知足不一樣的使用場景,好比設置文字顏色,背景顏色,自定義顯示時間,設置Snackbar顯示的具體位置,設置文字的對齊方式,甚至是向Snackbar佈局中添加View等,爲了實現這些需求,將一些方法整理出來,應該能夠節約開發者部分的時間.git
標題中的說的'一行代碼'在某些使用場景下有些誇大其詞,實際意思是指SnackbarUtils中的方法支持鏈式調用,能夠快捷的爲Snackbar設置多種效果!github
源碼及所在DEMO已上傳至GITHUB:SnackbarUtils,歡迎你們提Bug,或者有關於Snackbar新的使用場景也能夠交流,我會繼續把這個工具類繼續完善!工具
廢話很少說,直接上效果圖:佈局
已經實現的功能點: 1:設置Snackbar顯示時間長短 2:設置Snackbar背景顏色 3:設置TextView(@+id/snackbar_text)的文字顏色
4:設置Button(@+id/snackbar_action)的文字顏色
5:設置Snackbar背景的透明度
6:設置Snackbar顯示的位置
7:設置Button(@+id/snackbar_action)文字內容 及 點擊監聽
8:設置Snackbar展現完成 及 隱藏完成 的監聽
9:設置TextView(@+id/snackbar_text)左右兩側的圖片
10:設置TextView(@+id/snackbar_text)中文字的對齊方式
11:向Snackbar佈局中添加View(Google不建議,複雜的佈局應該使用DialogFragment進行展現)
12:設置Snackbar佈局的外邊距
13:設置Snackbar佈局的圓角半徑值
14:設置Snackbar佈局的圓角半徑值及邊框顏色及邊框寬度
15:設置Snackbar顯示在指定View的上方
16:設置Snackbar顯示在指定View的下方測試
SnackbarUtils代碼:ui
package com.jet.msnackbar; import android.annotation.TargetApi; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.os.Build; import android.support.annotation.ColorInt; import android.support.annotation.DrawableRes; import android.support.annotation.Nullable; import android.support.annotation.StringRes; import android.support.design.widget.CoordinatorLayout; import android.support.design.widget.Snackbar; import android.support.v4.widget.Space; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.TextView; import java.lang.ref.WeakReference; public class SnackbarUtils { //設置Snackbar背景顏色 private static final int color_info = 0XFF2094F3; private static final int color_confirm = 0XFF4CB04E; private static final int color_warning = 0XFFFEC005; private static final int color_danger = 0XFFF44336; //工具類當前持有的Snackbar實例 private static WeakReference<Snackbar> snackbarWeakReference; private SnackbarUtils(){ throw new RuntimeException("禁止無參建立實例"); } public SnackbarUtils(@Nullable WeakReference<Snackbar> snackbarWeakReference){ this.snackbarWeakReference = snackbarWeakReference; } /** * 獲取 mSnackbar * @return */ public Snackbar getSnackbar() { if(this.snackbarWeakReference != null && this.snackbarWeakReference.get()!=null){ return this.snackbarWeakReference.get(); }else { return null; } } /** * 初始化Snackbar實例 * 展現時間:Snackbar.LENGTH_SHORT * @param view * @param message * @return */ public static SnackbarUtils Short(View view, String message){ return new SnackbarUtils(new WeakReference<Snackbar>(Snackbar.make(view,message,Snackbar.LENGTH_SHORT))).backColor(0XFF323232); } /** * 初始化Snackbar實例 * 展現時間:Snackbar.LENGTH_LONG * @param view * @param message * @return */ public static SnackbarUtils Long(View view, String message){ return new SnackbarUtils(new WeakReference<Snackbar>(Snackbar.make(view,message,Snackbar.LENGTH_LONG))).backColor(0XFF323232); } /** * 初始化Snackbar實例 * 展現時間:Snackbar.LENGTH_INDEFINITE * @param view * @param message * @return */ public static SnackbarUtils Indefinite(View view, String message){ return new SnackbarUtils(new WeakReference<Snackbar>(Snackbar.make(view,message,Snackbar.LENGTH_INDEFINITE))).backColor(0XFF323232); } /** * 初始化Snackbar實例 * 展現時間:duration 毫秒 * @param view * @param message * @param duration 展現時長(毫秒) * @return */ public static SnackbarUtils Custom(View view, String message, int duration){ return new SnackbarUtils(new WeakReference<Snackbar>(Snackbar.make(view,message,Snackbar.LENGTH_SHORT).setDuration(duration))).backColor(0XFF323232); } /** * 設置mSnackbar背景色爲 color_info */ public SnackbarUtils info(){ Snackbar snackbar = getSnackbar(); if(snackbar!=null){ snackbar.getView().setBackgroundColor(color_info); } return new SnackbarUtils(snackbarWeakReference); } /** * 設置mSnackbar背景色爲 color_confirm */ public SnackbarUtils confirm(){ Snackbar snackbar = getSnackbar(); if(snackbar!=null){ snackbar.getView().setBackgroundColor(color_confirm); } return new SnackbarUtils(snackbarWeakReference); } /** * 設置Snackbar背景色爲 color_warning */ public SnackbarUtils warning(){ Snackbar snackbar = getSnackbar(); if(snackbar!=null){ snackbar.getView().setBackgroundColor(color_warning); } return new SnackbarUtils(snackbarWeakReference); } /** * 設置Snackbar背景色爲 color_warning */ public SnackbarUtils danger(){ Snackbar snackbar = getSnackbar(); if(snackbar!=null){ snackbar.getView().setBackgroundColor(color_danger); } return new SnackbarUtils(snackbarWeakReference); } /** * 設置Snackbar背景色 * @param backgroundColor */ public SnackbarUtils backColor(@ColorInt int backgroundColor){ Snackbar snackbar = getSnackbar(); if(snackbar!=null){ snackbar.getView().setBackgroundColor(backgroundColor); } return new SnackbarUtils(snackbarWeakReference); } /** * 設置TextView(@+id/snackbar_text)的文字顏色 * @param messageColor */ public SnackbarUtils messageColor(@ColorInt int messageColor){ Snackbar snackbar = getSnackbar(); if(snackbar!=null){ ((TextView)snackbar.getView().findViewById(R.id.snackbar_text)).setTextColor(messageColor); } return new SnackbarUtils(snackbarWeakReference); } /** * 設置Button(@+id/snackbar_action)的文字顏色 * @param actionTextColor */ public SnackbarUtils actionColor(@ColorInt int actionTextColor){ Snackbar snackbar = getSnackbar(); if(snackbar!=null){ ((Button)snackbar.getView().findViewById(R.id.snackbar_action)).setTextColor(actionTextColor); } return new SnackbarUtils(snackbarWeakReference); } /** * 設置 Snackbar背景色 + TextView(@+id/snackbar_text)的文字顏色 + Button(@+id/snackbar_action)的文字顏色 * @param backgroundColor * @param messageColor * @param actionTextColor */ public SnackbarUtils colors(@ColorInt int backgroundColor, @ColorInt int messageColor, @ColorInt int actionTextColor){ Snackbar snackbar = getSnackbar(); if(snackbar!=null){ snackbar.getView().setBackgroundColor(backgroundColor); ((TextView)snackbar.getView().findViewById(R.id.snackbar_text)).setTextColor(messageColor); ((Button)snackbar.getView().findViewById(R.id.snackbar_action)).setTextColor(actionTextColor); } return new SnackbarUtils(snackbarWeakReference); } /** * 設置Snackbar 背景透明度 * @param alpha * @return */ public SnackbarUtils alpha(float alpha){ Snackbar snackbar = getSnackbar(); if(snackbar!=null){ alpha = alpha>=1.0f?1.0f:(alpha<=0.0f?0.0f:alpha); snackbar.getView().setAlpha(alpha); } return new SnackbarUtils(snackbarWeakReference); } /** * 設置Snackbar顯示的位置 * @param gravity */ public SnackbarUtils gravityFrameLayout(int gravity){ Snackbar snackbar = getSnackbar(); if(snackbar!=null){ FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(snackbarWeakReference.get().getView().getLayoutParams().width,snackbarWeakReference.get().getView().getLayoutParams().height); params.gravity = gravity; snackbar.getView().setLayoutParams(params); } return new SnackbarUtils(snackbarWeakReference); } /** * 設置Snackbar顯示的位置,當Snackbar和CoordinatorLayout組合使用的時候 * @param gravity */ public SnackbarUtils gravityCoordinatorLayout(int gravity){ Snackbar snackbar = getSnackbar(); if(snackbar!=null){ CoordinatorLayout.LayoutParams params = new CoordinatorLayout.LayoutParams(snackbarWeakReference.get().getView().getLayoutParams().width,snackbarWeakReference.get().getView().getLayoutParams().height); params.gravity = gravity; snackbar.getView().setLayoutParams(params); } return new SnackbarUtils(snackbarWeakReference); } /** * 設置按鈕文字內容 及 點擊監聽 * {@link Snackbar#setAction(CharSequence, View.OnClickListener)} * @param resId * @param listener * @return */ public SnackbarUtils setAction(@StringRes int resId, View.OnClickListener listener){ Snackbar snackbar = getSnackbar(); if(snackbar!=null){ return setAction(snackbar.getView().getResources().getText(resId), listener); }else { return new SnackbarUtils(snackbarWeakReference); } } /** * 設置按鈕文字內容 及 點擊監聽 * {@link Snackbar#setAction(CharSequence, View.OnClickListener)} * @param text * @param listener * @return */ public SnackbarUtils setAction(CharSequence text, View.OnClickListener listener){ Snackbar snackbar = getSnackbar(); if(snackbar!=null){ snackbar.setAction(text,listener); } return new SnackbarUtils(snackbarWeakReference); } /** * 設置 mSnackbar 展現完成 及 隱藏完成 的監聽 * @param setCallback * @return */ public SnackbarUtils setCallback(Snackbar.Callback setCallback){ Snackbar snackbar = getSnackbar(); if(snackbar!=null){ snackbar.setCallback(setCallback); } return new SnackbarUtils(snackbarWeakReference); } /** * 設置TextView(@+id/snackbar_text)左右兩側的圖片 * @param leftDrawable * @param rightDrawable * @return */ public SnackbarUtils leftAndRightDrawable(@Nullable @DrawableRes Integer leftDrawable, @Nullable @DrawableRes Integer rightDrawable){ Snackbar snackbar = getSnackbar(); if(snackbar!=null){ Drawable drawableLeft = null; Drawable drawableRight = null; if(leftDrawable!=null){ try { drawableLeft = snackbar.getView().getResources().getDrawable(leftDrawable.intValue()); }catch (Exception e){ } } if(rightDrawable!=null){ try { drawableRight = snackbar.getView().getResources().getDrawable(rightDrawable.intValue()); }catch (Exception e){ } } return leftAndRightDrawable(drawableLeft,drawableRight); }else { return new SnackbarUtils(snackbarWeakReference); } } /** * 設置TextView(@+id/snackbar_text)左右兩側的圖片 * @param leftDrawable * @param rightDrawable * @return */ public SnackbarUtils leftAndRightDrawable(@Nullable Drawable leftDrawable, @Nullable Drawable rightDrawable){ Snackbar snackbar = getSnackbar(); if(snackbar!=null){ TextView message = (TextView) snackbar.getView().findViewById(R.id.snackbar_text); LinearLayout.LayoutParams paramsMessage = (LinearLayout.LayoutParams) message.getLayoutParams(); paramsMessage = new LinearLayout.LayoutParams(paramsMessage.width, paramsMessage.height,0.0f); message.setLayoutParams(paramsMessage); message.setCompoundDrawablePadding(message.getPaddingLeft()); int textSize = (int) message.getTextSize(); Log.e("Jet","textSize:"+textSize); if(leftDrawable!=null){ leftDrawable.setBounds(0,0,textSize,textSize); } if(rightDrawable!=null){ rightDrawable.setBounds(0,0,textSize,textSize); } message.setCompoundDrawables(leftDrawable,null,rightDrawable,null); LinearLayout.LayoutParams paramsSpace = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT,1.0f); ((Snackbar.SnackbarLayout)snackbar.getView()).addView(new Space(snackbar.getView().getContext()),1,paramsSpace); } return new SnackbarUtils(snackbarWeakReference); } /** * 設置TextView(@+id/snackbar_text)中文字的對齊方式 居中 * @return */ @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) public SnackbarUtils messageCenter(){ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){ Snackbar snackbar = getSnackbar(); if(snackbar!=null){ TextView message = (TextView) snackbar.getView().findViewById(R.id.snackbar_text); //View.setTextAlignment須要SDK>=17 message.setTextAlignment(View.TEXT_ALIGNMENT_GRAVITY); message.setGravity(Gravity.CENTER); } } return new SnackbarUtils(snackbarWeakReference); } /** * 設置TextView(@+id/snackbar_text)中文字的對齊方式 居右 * @return */ @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) public SnackbarUtils messageRight(){ if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){ Snackbar snackbar = getSnackbar(); if(snackbar!=null){ TextView message = (TextView) snackbar.getView().findViewById(R.id.snackbar_text); //View.setTextAlignment須要SDK>=17 message.setTextAlignment(View.TEXT_ALIGNMENT_GRAVITY); message.setGravity(Gravity.CENTER_VERTICAL|Gravity.RIGHT); } } return new SnackbarUtils(snackbarWeakReference); } /** * 向Snackbar佈局中添加View(Google不建議,複雜的佈局應該使用DialogFragment進行展現) * @param layoutId 要添加的View的佈局文件ID * @param index * @return */ public SnackbarUtils addView(int layoutId, int index) { Snackbar snackbar = getSnackbar(); if(snackbar!=null){ //加載佈局文件新建View View addView = LayoutInflater.from(snackbar.getView().getContext()).inflate(layoutId,null); return addView(addView,index); }else { return new SnackbarUtils(snackbarWeakReference); } } /** * 向Snackbar佈局中添加View(Google不建議,複雜的佈局應該使用DialogFragment進行展現) * @param addView * @param index * @return */ public SnackbarUtils addView(View addView, int index) { Snackbar snackbar = getSnackbar(); if(snackbar!=null){ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT);//設置新建佈局參數 //設置新建View在Snackbar內垂直居中顯示 params.gravity= Gravity.CENTER_VERTICAL; addView.setLayoutParams(params); ((Snackbar.SnackbarLayout)snackbar.getView()).addView(addView,index); } return new SnackbarUtils(snackbarWeakReference); } /** * 設置Snackbar佈局的外邊距 * 注:經試驗發現,調用margins後再調用 gravityFrameLayout,則margins無效. * 爲保證margins有效,應該先調用 gravityFrameLayout,在 show() 以前調用 margins * @param margin * @return */ public SnackbarUtils margins(int margin){ Snackbar snackbar = getSnackbar(); if(snackbar!=null){ return margins(margin,margin,margin,margin); }else { return new SnackbarUtils(snackbarWeakReference); } } /** * 設置Snackbar佈局的外邊距 * 注:經試驗發現,調用margins後再調用 gravityFrameLayout,則margins無效. * 爲保證margins有效,應該先調用 gravityFrameLayout,在 show() 以前調用 margins * @param left * @param top * @param right * @param bottom * @return */ public SnackbarUtils margins(int left, int top, int right, int bottom){ Snackbar snackbar = getSnackbar(); if(snackbar!=null){ ViewGroup.LayoutParams params = snackbar.getView().getLayoutParams(); ((ViewGroup.MarginLayoutParams) params).setMargins(left,top,right,bottom); snackbar.getView().setLayoutParams(params); } return new SnackbarUtils(snackbarWeakReference); } /** * 經試驗發現: * 執行過{@link SnackbarUtils#backColor(int)}後:background instanceof ColorDrawable * 未執行過{@link SnackbarUtils#backColor(int)}:background instanceof GradientDrawable * @return */ /* public SnackbarUtils radius(){ Drawable background = snackbarWeakReference.get().getView().getBackground(); if(background instanceof GradientDrawable){ Log.e("Jet","radius():GradientDrawable"); } if(background instanceof ColorDrawable){ Log.e("Jet","radius():ColorDrawable"); } if(background instanceof StateListDrawable){ Log.e("Jet","radius():StateListDrawable"); } Log.e("Jet","radius()background:"+background.getClass().getSimpleName()); return new SnackbarUtils(mSnackbar); } */ /** * 經過SnackBar如今的背景,獲取其設置圓角值時候所需的GradientDrawable實例 * @param backgroundOri * @return */ private GradientDrawable getRadiusDrawable(Drawable backgroundOri){ GradientDrawable background = null; if(backgroundOri instanceof GradientDrawable){ background = (GradientDrawable) backgroundOri; }else if(backgroundOri instanceof ColorDrawable){ int backgroundColor = ((ColorDrawable)backgroundOri).getColor(); background = new GradientDrawable(); background.setColor(backgroundColor); }else { } return background; } /** * 設置Snackbar佈局的圓角半徑值 * @param radius 圓角半徑 * @return */ public SnackbarUtils radius(float radius){ Snackbar snackbar = getSnackbar(); if(snackbar!=null){ //將要設置給mSnackbar的背景 GradientDrawable background = getRadiusDrawable(snackbar.getView().getBackground()); if(background != null){ radius = radius<=0?12:radius; background.setCornerRadius(radius); snackbar.getView().setBackgroundDrawable(background); } } return new SnackbarUtils(snackbarWeakReference); } /** * 設置Snackbar佈局的圓角半徑值及邊框顏色及邊框寬度 * @param radius * @param strokeWidth * @param strokeColor * @return */ public SnackbarUtils radius(int radius, int strokeWidth, @ColorInt int strokeColor){ Snackbar snackbar = getSnackbar(); if(snackbar!=null){ //將要設置給mSnackbar的背景 GradientDrawable background = getRadiusDrawable(snackbar.getView().getBackground()); if(background != null){ radius = radius<=0?12:radius; strokeWidth = strokeWidth<=0?1:(strokeWidth>=snackbar.getView().findViewById(R.id.snackbar_text).getPaddingTop()?2:strokeWidth); background.setCornerRadius(radius); background.setStroke(strokeWidth,strokeColor); snackbar.getView().setBackgroundDrawable(background); } } return new SnackbarUtils(snackbarWeakReference); } /** * 計算單行的Snackbar的高度值(單位 pix) * @return */ private int calculateSnackBarHeight(){ int SnackbarHeight = ScreenUtil.dp2px(snackbarWeakReference.get().getView().getContext(),28) + ScreenUtil.sp2px(snackbarWeakReference.get().getView().getContext(),14); Log.e("Jet","直接獲取MessageView高度:"+snackbarWeakReference.get().getView().findViewById(R.id.snackbar_text).getHeight()); return SnackbarHeight; } /** * 設置Snackbar顯示在指定View的上方 * 注:暫時僅支持單行的Snackbar,由於{@link SnackbarUtils#calculateSnackBarHeight()}暫時僅支持單行Snackbar的高度計算 * @param targetView 指定View * @param contentViewTop Activity中的View佈局區域 距離屏幕頂端的距離 * @param marginLeft 左邊距 * @param marginRight 右邊距 * @return */ public SnackbarUtils above(View targetView, int contentViewTop, int marginLeft, int marginRight){ Snackbar snackbar = getSnackbar(); if(snackbar!=null){ marginLeft = marginLeft<=0?0:marginLeft; marginRight = marginRight<=0?0:marginRight; int[] locations = new int[2]; targetView.getLocationOnScreen(locations); Log.e("Jet","距離屏幕左側:"+locations[0]+"==距離屏幕頂部:"+locations[1]); int snackbarHeight = calculateSnackBarHeight(); Log.e("Jet","Snackbar高度:"+snackbarHeight); //必須保證指定View的頂部可見 且 單行Snackbar能夠完整的展現 if(locations[1] >= contentViewTop+snackbarHeight){ gravityFrameLayout(Gravity.BOTTOM); ViewGroup.LayoutParams params = snackbar.getView().getLayoutParams(); ((ViewGroup.MarginLayoutParams) params).setMargins(marginLeft,0,marginRight,snackbar.getView().getResources().getDisplayMetrics().heightPixels-locations[1]); snackbar.getView().setLayoutParams(params); } } return new SnackbarUtils(snackbarWeakReference); } /** * 設置Snackbar顯示在指定View的下方 * 注:暫時僅支持單行的Snackbar,由於{@link SnackbarUtils#calculateSnackBarHeight()}暫時僅支持單行Snackbar的高度計算 * @param targetView 指定View * @param contentViewTop Activity中的View佈局區域 距離屏幕頂端的距離 * @param marginLeft 左邊距 * @param marginRight 右邊距 * @return */ public SnackbarUtils bellow(View targetView, int contentViewTop, int marginLeft, int marginRight){ Snackbar snackbar = getSnackbar(); if(snackbar!=null){ marginLeft = marginLeft<=0?0:marginLeft; marginRight = marginRight<=0?0:marginRight; int[] locations = new int[2]; targetView.getLocationOnScreen(locations); int snackbarHeight = calculateSnackBarHeight(); int screenHeight = ScreenUtil.getScreenHeight(snackbar.getView().getContext()); //必須保證指定View的底部可見 且 單行Snackbar能夠完整的展現 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){ //爲何要'+2'? 由於在Android L(Build.VERSION_CODES.LOLLIPOP)以上,例如Button會有必定的'陰影(shadow)',陰影的大小由'高度(elevation)'決定. //爲了在Android L以上的系統中展現的Snackbar不要覆蓋targetView的陰影部分太大比例,因此人爲減少2px的layout_marginBottom屬性. if(locations[1]+targetView.getHeight()>=contentViewTop&&locations[1]+targetView.getHeight()+snackbarHeight+2<=screenHeight){ gravityFrameLayout(Gravity.BOTTOM); ViewGroup.LayoutParams params = snackbar.getView().getLayoutParams(); ((ViewGroup.MarginLayoutParams) params).setMargins(marginLeft,0,marginRight,screenHeight - (locations[1]+targetView.getHeight()+snackbarHeight+2)); snackbar.getView().setLayoutParams(params); } }else { if(locations[1]+targetView.getHeight()>=contentViewTop&&locations[1]+targetView.getHeight()+snackbarHeight<=screenHeight){ gravityFrameLayout(Gravity.BOTTOM); ViewGroup.LayoutParams params = snackbar.getView().getLayoutParams(); ((ViewGroup.MarginLayoutParams) params).setMargins(marginLeft,0,marginRight,screenHeight - (locations[1]+targetView.getHeight()+snackbarHeight)); snackbar.getView().setLayoutParams(params); } } } return new SnackbarUtils(snackbarWeakReference); } /** * 顯示 mSnackbar */ public void show(){ if(getSnackbar()!=null){ snackbarWeakReference.get().show(); }else { } } }
DEMO中還包括另外一個工具類ScreenUtil,及測試Activity文件,詳情可查看GITHUB:SnackbarUtils.歡迎你們提Bug,謹慎輕拍哈!this
That's all !code