Android Snackbar简单解析
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Snackbar简单解析相关的知识,希望对你有一定的参考价值。
偶然间发现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;
- @Override
- public void onShown(Snackbar sb) {
- // Stub implementation to make API check happy.
- }
- @Override
- public 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}
- */
- @NonNull
- public 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 it
- return (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 fallback
- fallback = (ViewGroup) view;
- }
- }
- if (view != null) {
- // Else, we will loop and crawl up the view hierarchy and try to find a parent
- final 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 fallback
- return fallback;
- }
- /**
- * 更新文本。看这意思,是可以给一个正在显示的scankbar更新文本?
- */
- @NonNull
- public 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
- */
- @NonNull
- public 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() {
- @Override
- public void onClick(View view) {
- listener.onClick(view);
- // Now dismiss the Snackbar
- dispatchDismiss(BaseCallback.DISMISS_EVENT_ACTION);
- }
- });
- }
- return this;
- }
- /**
- * 设置点击动作的文本颜色
- */
- @NonNull
- public 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
- @NonNull
- public 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 called
- mCallback = callback;
- return this;
- }
- ...
- }
搜嘎,简略的读下源码后发现这个类很简单,那么更奇葩的用法来了:
- @Override
- public void onClick(View v) {
- Snackbar sb = Snackbar.make(v,"aa",Snackbar.LENGTH_LONG).setAction("是吗?", new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- //点击了"是吗?"字符串操作
- }
- }).setActionTextColor(Color.RED).setText("aa是不够的").addCallback(new BaseTransientBottomBar.BaseCallback<Snackbar>() {
- @Override
- public void onDismissed(Snackbar transientBottomBar, int event) {
- super.onDismissed(transientBottomBar, event);
- Log.d("MainActivity","onDismissed");
- }
- @Override
- public 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了。动手练习。
以上是关于Android Snackbar简单解析的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Flutter 中为 Snack Bar 编写一个简单的测试?