偶然间发现android中有Snackbar类,还是有点意思,类似于toast。与toast相比,最明显的区别是:Snackbar只能在屏幕底部显示。其他用法基本与toast相似。
接下来我简略翻译下部分源码:
先来张效果图吧,静态图:
大概的用法呢?:
Snackbar.make(btn,"Snackbar 测试",Snackbar.LENGTH_INDEFINITE).show();
//记得引入库:
compile 'com.android.support:design:xx.xx.xx'
接下来我简略翻译下部分源码:
包名
package android.support.design.widget;/*** Snackbars为用户操作提供一个轻量级的反馈,* 他在屏幕底部显示一个简略的消息,* snackbars出现在屏幕上的所有其他要素之上,* 同一时间只会显示一个scankbar,* 在一定时间后他会自动消失,* 如果传递给scankbar的父容器是CoordinatorLayout,则用户可右滑关闭他。* Snackbars可以包含一个动作,当你调用setAction(CharSequence, android.view.View.OnClickListener)方法时(设置一个文本,并提供一个关于该文本的点击事件。如果设置了,则文本显示在scankbar的内部右侧)* 如果你讲关注snackbar的显示或隐藏事件,你可以设置回调函数监控addCallback(BaseCallback)*/
public final class Snackbar extends BaseTransientBottomBar<Snackbar> {/*** 无限期的显示一个Snackbar。意思也就是说这个Snackbar在被调用show()后显示,直到被调用关闭,或者有另一个被显示时才会关闭。**/public static final int LENGTH_INDEFINITE = BaseTransientBottomBar.LENGTH_INDEFINITE;public static final int LENGTH_SHORT = BaseTransientBottomBar.LENGTH_SHORT;public static final int LENGTH_LONG = BaseTransientBottomBar.LENGTH_LONG;/*** Snackbar的回调类.** @see BaseTransientBottomBar#addCallback(BaseCallback)*/public static class Callback extends BaseCallback<Snackbar> {/** 表示Snackbar被滑动关闭.*/public static final int DISMISS_EVENT_SWIPE = BaseCallback.DISMISS_EVENT_SWIPE;/** 表示Snackbar被点击action后关闭.*/public static final int DISMISS_EVENT_ACTION = BaseCallback.DISMISS_EVENT_ACTION;/** 表示Snackbar显示到一定时间后关闭.*/public static final int DISMISS_EVENT_TIMEOUT = BaseCallback.DISMISS_EVENT_TIMEOUT;/** 表示Snackbar被调用dismiss()后关闭.*/public static final int DISMISS_EVENT_MANUAL = BaseCallback.DISMISS_EVENT_MANUAL;/** 表示Snackbar被一个新的Snackbar显示时关闭.*/public static final int DISMISS_EVENT_CONSECUTIVE = BaseCallback.DISMISS_EVENT_CONSECUTIVE;@Overridepublic void onShown(Snackbar sb) {// Stub implementation to make API check happy.}@Overridepublic void onDismissed(Snackbar transientBottomBar, @DismissEvent int event) {// Stub implementation to make API check happy.}}private BaseCallback<Snackbar> mCallback;private Snackbar(ViewGroup parent, View content, ContentViewCallback contentViewCallback) {super(parent, content, contentViewCallback);}/*** 构造一个对象** Snackbar会尝试从给定的容器中向上寻找一个合适的父容器来托管他的view. 他的父容器会被认为是CoordinatorLayout或者是decorView.先找到了其中的某一个就结束查找。* 如果给定的容器中包含CoordinatorLayout布局,那么这个Scankbar将会获得更多的特性,比喻滑动删除scankbar.** @param view The view to find a parent from.* @param text The text to show. Can be formatted text.* @param duration How long to display the message. Either {@link #LENGTH_SHORT} or {@link* #LENGTH_LONG}*/@NonNullpublic static Snackbar make(@NonNull View view, @NonNull CharSequence text,@Duration int duration) {final ViewGroup parent = findSuitableParent(view);if (parent == null) {throw new IllegalArgumentException("No suitable parent found from the given view. "+ "Please provide a valid view.");}final LayoutInflater inflater = LayoutInflater.from(parent.getContext());final SnackbarContentLayout content =(SnackbarContentLayout) inflater.inflate(R.layout.design_layout_snackbar_include, parent, false);final Snackbar snackbar = new Snackbar(parent, content, content);snackbar.setText(text);snackbar.setDuration(duration);return snackbar;}//查找合适的父容器private static ViewGroup findSuitableParent(View view) {ViewGroup fallback = null;do {if (view instanceof CoordinatorLayout) {//如果是CoordinatorLayout// We've found a CoordinatorLayout, use itreturn (ViewGroup) view;} else if (view instanceof FrameLayout) {if (view.getId() == android.R.id.content) {// If we've hit the decor content view, then we didn't find a CoL in the// hierarchy, so use it.return (ViewGroup) view;} else {// It's not the content view but we'll use it as our fallbackfallback = (ViewGroup) view;}}if (view != null) {// Else, we will loop and crawl up the view hierarchy and try to find a parentfinal ViewParent parent = view.getParent();view = parent instanceof View ? (View) parent : null;}} while (view != null);// If we reach here then we didn't find a CoL or a suitable content view so we'll fallbackreturn fallback;}/*** 更新文本。看这意思,是可以给一个正在显示的scankbar更新文本?*/@NonNullpublic Snackbar setText(@NonNull CharSequence message) {final SnackbarContentLayout contentLayout = (SnackbarContentLayout) mView.getChildAt(0);final TextView tv = contentLayout.getMessageView();tv.setText(message);return this;}/*** 设置一个带点击动作的文本,以及回调函数。* 点击文本的同时关闭scankbar。* 设置了文本则显示,并设置事件。如果没有设置,则隐藏。看来是已有的布局了* @param text Text to display for the action* @param listener callback to be invoked when the action is clicked*/@NonNullpublic Snackbar setAction(CharSequence text, final View.OnClickListener listener) {final SnackbarContentLayout contentLayout = (SnackbarContentLayout) mView.getChildAt(0);final TextView tv = contentLayout.getActionView();if (TextUtils.isEmpty(text) || listener == null) {tv.setVisibility(View.GONE);tv.setOnClickListener(null);} else {tv.setVisibility(View.VISIBLE);tv.setText(text);tv.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {listener.onClick(view);// Now dismiss the SnackbardispatchDismiss(BaseCallback.DISMISS_EVENT_ACTION);}});}return this;}/*** 设置点击动作的文本颜色*/@NonNullpublic Snackbar setActionTextColor(ColorStateList colors) {final SnackbarContentLayout contentLayout = (SnackbarContentLayout) mView.getChildAt(0);final TextView tv = contentLayout.getActionView();tv.setTextColor(colors);return this;}/*** 设置回调函数,来监控scankbar的显示与隐藏动作. * 什么?这个方法过时了?* 请使用addCallback(BaseCallback)和removeCallback(BaseCallback)函数.** @param callback Callback to notify when transient bottom bar events occur.* @deprecated Use {@link #addCallback(BaseCallback)}* @see Callback* @see #addCallback(BaseCallback)* @see #removeCallback(BaseCallback)*/@Deprecated@NonNullpublic Snackbar setCallback(Callback callback) {// The logic in this method emulates what we had before support for multiple// registered callbacks.if (mCallback != null) {removeCallback(mCallback);}if (callback != null) {addCallback(callback);}// Update the deprecated field so that we can remove the passed callback the next// time we're calledmCallback = callback;return this;}...
}
搜嘎,简略的读下源码后发现这个类很简单,那么更奇葩的用法来了:
@Override
public void onClick(View v) {Snackbar sb = Snackbar.make(v,"aa",Snackbar.LENGTH_LONG).setAction("是吗?", new View.OnClickListener() {@Overridepublic void onClick(View v) {//点击了"是吗?"字符串操作}}).setActionTextColor(Color.RED).setText("aa是不够的").addCallback(new BaseTransientBottomBar.BaseCallback<Snackbar>() {@Overridepublic void onDismissed(Snackbar transientBottomBar, int event) {super.onDismissed(transientBottomBar, event);Log.d("MainActivity","onDismissed");}@Overridepublic void onShown(Snackbar transientBottomBar) {super.onShown(transientBottomBar);Log.d("MainActivity","onShown");}});sb.show();//sb.isShown();//sb.dismiss();}
注意看,Snackbar sb = make(v,"aa",......
第一个参数我给的v,就是当前点击的按钮,什么情况?
源码中说了,他会从这个view起想上查找一个合适的父容器,直到找到CoordinatorLayout或者decorView。先找到了其中的某一个就结束查找。如果找到了CoordinatorLayout,则可以有右滑删除功能哦。
如果想设置显示的内容,和整个背景色,也很简单。自己添加布局就可以了,跟toast一样,没多大意义不说了。
这么简单,不贴demo了。动手练习。