偶然间发现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了。动手练习。