Android Snackbar简单解析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Snackbar简单解析相关的知识,希望对你有一定的参考价值。

偶然间发现android中有Snackbar类,还是有点意思,类似于toast。与toast相比,最明显的区别是:Snackbar只能在屏幕底部显示。其他用法基本与toast相似。

先来张效果图吧,静态图:

技术分享


大概的用法呢?:

  1. Snackbar.make(btn,"Snackbar 测试",Snackbar.LENGTH_INDEFINITE).show();  
  2. //记得引入库:  
  3. compile ‘com.android.support:design:xx.xx.xx‘  


接下来我简略翻译下部分源码:

  1. 包名  
  2. package android.support.design.widget;  
  3.   
  4. /**  
  5.  * Snackbars为用户操作提供一个轻量级的反馈,  
  6.  * 他在屏幕底部显示一个简略的消息,  
  7.  * snackbars出现在屏幕上的所有其他要素之上,  
  8.  * 同一时间只会显示一个scankbar,  
  9.  * 在一定时间后他会自动消失,  
  10.  * 如果传递给scankbar的父容器是CoordinatorLayout,则用户可右滑关闭他。  
  11.  * Snackbars可以包含一个动作,当你调用setAction(CharSequence,      android.view.View.OnClickListener)方法时(设置一个文本,并提供一个关于该文本的点击事件。如果设置了,则文本显示在scankbar的内部右侧)  
  12.  * 如果你讲关注snackbar的显示或隐藏事件,你可以设置回调函数监控addCallback(BaseCallback)  
  13.  */  
  14. public final class Snackbar extends BaseTransientBottomBar<Snackbar> {  
  15.   
  16.     /**  
  17.      *      无限期的显示一个Snackbar。意思也就是说这个Snackbar在被调用show()后显示,直到被调用关闭,或者有另一个被显示时才会关闭。  
  18.      *  
  19.      */  
  20.     public static final int LENGTH_INDEFINITE = BaseTransientBottomBar.LENGTH_INDEFINITE;  
  21.   
  22.     public static final int LENGTH_SHORT = BaseTransientBottomBar.LENGTH_SHORT;  
  23.   
  24.     public static final int LENGTH_LONG = BaseTransientBottomBar.LENGTH_LONG;  
  25.   
  26.     /**  
  27.      * Snackbar的回调类.  
  28.      *  
  29.      * @see BaseTransientBottomBar#addCallback(BaseCallback)  
  30.      */  
  31.     public static class Callback extends BaseCallback<Snackbar> {  
  32.         /** 表示Snackbar被滑动关闭.*/  
  33.         public static final int DISMISS_EVENT_SWIPE = BaseCallback.DISMISS_EVENT_SWIPE;  
  34.         /** 表示Snackbar被点击action后关闭.*/  
  35.         public static final int DISMISS_EVENT_ACTION = BaseCallback.DISMISS_EVENT_ACTION;  
  36.         /** 表示Snackbar显示到一定时间后关闭.*/  
  37.         public static final int DISMISS_EVENT_TIMEOUT = BaseCallback.DISMISS_EVENT_TIMEOUT;  
  38.         /** 表示Snackbar被调用dismiss()后关闭.*/  
  39.         public static final int DISMISS_EVENT_MANUAL = BaseCallback.DISMISS_EVENT_MANUAL;  
  40.         /** 表示Snackbar被一个新的Snackbar显示时关闭.*/  
  41.         public static final int DISMISS_EVENT_CONSECUTIVE = BaseCallback.DISMISS_EVENT_CONSECUTIVE;  
  42.   
  43.         @Override  
  44.         public void onShown(Snackbar sb) {  
  45.             // Stub implementation to make API check happy.  
  46.         }  
  47.   
  48.         @Override  
  49.         public void onDismissed(Snackbar transientBottomBar, @DismissEvent int event) {  
  50.             // Stub implementation to make API check happy.  
  51.         }  
  52.     }  
  53.   
  54.     private BaseCallback<Snackbar> mCallback;  
  55.   
  56.     private Snackbar(ViewGroup parent, View content, ContentViewCallback contentViewCallback) {  
  57.         super(parent, content, contentViewCallback);  
  58.     }  
  59.   
  60.     /**  
  61.      * 构造一个对象  
  62.      *  
  63.      * Snackbar会尝试从给定的容器中向上寻找一个合适的父容器来托管他的view. 他的父容器会被认为是CoordinatorLayout或者是decorView.先找到了其中的某一个就结束查找。  
  64.      * 如果给定的容器中包含CoordinatorLayout布局,那么这个Scankbar将会获得更多的特性,比喻滑动删除scankbar.  
  65.      *  
  66.      * @param view     The view to find a parent from.  
  67.      * @param text     The text to show.  Can be formatted text.  
  68.      * @param duration How long to display the message.  Either {@link #LENGTH_SHORT} or {@link  
  69.      *                 #LENGTH_LONG}  
  70.      */  
  71.     @NonNull  
  72.     public static Snackbar make(@NonNull View view, @NonNull CharSequence text,  
  73.             @Duration int duration) {  
  74.         final ViewGroup parent = findSuitableParent(view);  
  75.         if (parent == null) {  
  76.             throw new IllegalArgumentException("No suitable parent found from the given view. "  
  77.                     + "Please provide a valid view.");  
  78.         }  
  79.   
  80.         final LayoutInflater inflater = LayoutInflater.from(parent.getContext());  
  81.         final SnackbarContentLayout content =  
  82.                 (SnackbarContentLayout) inflater.inflate(  
  83.                         R.layout.design_layout_snackbar_include, parent, false);  
  84.         final Snackbar snackbar = new Snackbar(parent, content, content);  
  85.         snackbar.setText(text);  
  86.         snackbar.setDuration(duration);  
  87.         return snackbar;  
  88.     }  
  89.   
  90.     //查找合适的父容器  
  91.     private static ViewGroup findSuitableParent(View view) {  
  92.         ViewGroup fallback = null;  
  93.         do {  
  94.           
  95.             if (view instanceof CoordinatorLayout) {//如果是CoordinatorLayout  
  96.                 // We‘ve found a CoordinatorLayout, use it  
  97.                 return (ViewGroup) view;  
  98.             } else if (view instanceof FrameLayout) {  
  99.                 if (view.getId() == android.R.id.content) {  
  100.                     // If we‘ve hit the decor content view, then we didn‘t find a CoL in the  
  101.                     // hierarchy, so use it.  
  102.                     return (ViewGroup) view;  
  103.                 } else {  
  104.                     // It‘s not the content view but we‘ll use it as our fallback  
  105.                     fallback = (ViewGroup) view;  
  106.                 }  
  107.             }  
  108.   
  109.             if (view != null) {  
  110.                 // Else, we will loop and crawl up the view hierarchy and try to find a parent  
  111.                 final ViewParent parent = view.getParent();  
  112.                 view = parent instanceof View ? (View) parent : null;  
  113.             }  
  114.         } while (view != null);  
  115.   
  116.         // If we reach here then we didn‘t find a CoL or a suitable content view so we‘ll fallback  
  117.         return fallback;  
  118.     }  
  119.   
  120.     /**  
  121.      * 更新文本。看这意思,是可以给一个正在显示的scankbar更新文本?  
  122.      */  
  123.     @NonNull  
  124.     public Snackbar setText(@NonNull CharSequence message) {  
  125.         final SnackbarContentLayout contentLayout = (SnackbarContentLayout) mView.getChildAt(0);  
  126.         final TextView tv = contentLayout.getMessageView();  
  127.         tv.setText(message);  
  128.         return this;  
  129.     }  
  130.   
  131.     /**  
  132.      * 设置一个带点击动作的文本,以及回调函数。  
  133.      * 点击文本的同时关闭scankbar。  
  134.      * 设置了文本则显示,并设置事件。如果没有设置,则隐藏。看来是已有的布局了  
  135.      * @param text     Text to display for the action  
  136.      * @param listener callback to be invoked when the action is clicked  
  137.      */  
  138.     @NonNull  
  139.     public Snackbar setAction(CharSequence text, final View.OnClickListener listener) {  
  140.         final SnackbarContentLayout contentLayout = (SnackbarContentLayout) mView.getChildAt(0);  
  141.         final TextView tv = contentLayout.getActionView();  
  142.   
  143.         if (TextUtils.isEmpty(text) || listener == null) {  
  144.             tv.setVisibility(View.GONE);  
  145.             tv.setOnClickListener(null);  
  146.         } else {  
  147.             tv.setVisibility(View.VISIBLE);  
  148.             tv.setText(text);  
  149.             tv.setOnClickListener(new View.OnClickListener() {  
  150.                 @Override  
  151.                 public void onClick(View view) {  
  152.                     listener.onClick(view);  
  153.                     // Now dismiss the Snackbar  
  154.                     dispatchDismiss(BaseCallback.DISMISS_EVENT_ACTION);  
  155.                 }  
  156.             });  
  157.         }  
  158.         return this;  
  159.     }  
  160.   
  161.     /**  
  162.      * 设置点击动作的文本颜色  
  163.      */  
  164.     @NonNull  
  165.     public Snackbar setActionTextColor(ColorStateList colors) {  
  166.         final SnackbarContentLayout contentLayout = (SnackbarContentLayout) mView.getChildAt(0);  
  167.         final TextView tv = contentLayout.getActionView();  
  168.         tv.setTextColor(colors);  
  169.         return this;  
  170.     }  
  171.   
  172.     /**  
  173.      * 设置回调函数,来监控scankbar的显示与隐藏动作.   
  174.      * 什么?这个方法过时了?  
  175.      * 请使用addCallback(BaseCallback)和removeCallback(BaseCallback)函数.  
  176.      *  
  177.      * @param callback Callback to notify when transient bottom bar events occur.  
  178.      * @deprecated Use {@link #addCallback(BaseCallback)}  
  179.      * @see Callback  
  180.      * @see #addCallback(BaseCallback)  
  181.      * @see #removeCallback(BaseCallback)  
  182.      */  
  183.     @Deprecated  
  184.     @NonNull  
  185.     public Snackbar setCallback(Callback callback) {  
  186.         // The logic in this method emulates what we had before support for multiple  
  187.         // registered callbacks.  
  188.         if (mCallback != null) {  
  189.             removeCallback(mCallback);  
  190.         }  
  191.         if (callback != null) {  
  192.             addCallback(callback);  
  193.         }  
  194.         // Update the deprecated field so that we can remove the passed callback the next  
  195.         // time we‘re called  
  196.         mCallback = callback;  
  197.         return this;  
  198.     }  
  199.   
  200.     ...  
  201. }  


搜嘎,简略的读下源码后发现这个类很简单,那么更奇葩的用法来了:

  1. @Override  
  2. public void onClick(View v) {  
  3.     Snackbar sb = Snackbar.make(v,"aa",Snackbar.LENGTH_LONG).setAction("是吗?", new View.OnClickListener() {  
  4.         @Override  
  5.         public void onClick(View v) {  
  6.             //点击了"是吗?"字符串操作  
  7.         }  
  8.     }).setActionTextColor(Color.RED).setText("aa是不够的").addCallback(new BaseTransientBottomBar.BaseCallback<Snackbar>() {  
  9.         @Override  
  10.         public void onDismissed(Snackbar transientBottomBar, int event) {  
  11.             super.onDismissed(transientBottomBar, event);  
  12.             Log.d("MainActivity","onDismissed");  
  13.         }  
  14.   
  15.         @Override  
  16.         public void onShown(Snackbar transientBottomBar) {  
  17.             super.onShown(transientBottomBar);  
  18.             Log.d("MainActivity","onShown");  
  19.         }  
  20.     });  
  21.     sb.show();  
  22.     //sb.isShown();  
  23.     //sb.dismiss();  
  24.   
  25. }  



注意看,Snackbar sb = make(v,"aa",......
第一个参数我给的v,就是当前点击的按钮,什么情况?
源码中说了,他会从这个view起想上查找一个合适的父容器,直到找到CoordinatorLayout或者decorView。先找到了其中的某一个就结束查找。如果找到了CoordinatorLayout,则可以有右滑删除功能哦。


如果想设置显示的内容,和整个背景色,也很简单。自己添加布局就可以了,跟toast一样,没多大意义不说了。




这么简单,不贴demo了。动手练习。


















以上是关于Android Snackbar简单解析的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Flutter 中为 Snack Bar 编写一个简单的测试?

(android) 小吃吧结束后如何关闭活动?

Snackbar.setCallback() 在 Android AppCompat 中无法解析

从右到左 SnackBar

角材质覆盖 SnackBar 组件的默认样式

无法解析 floatinbuttonAction 和snackbar