Google在2014年发布了Material Design语言,紧接着第二年发布了官方support包,可以支持在低版本上手机使用这些控件。但是这么长时间过去了,国内主流app几乎都没有遵循这种规范,原因也很好理解了,这篇文章分析的比较到位(为什么Material Design没在国产App中流行起来)。最近有机会重头开始做一个APP,这是一个很好的机会践行Material Design,这里把学习support包的一些心得记录一下,与大家共同交流学习。首先是第一个控件Snackbar:
Snackbar和Toast很相似,不过是从屏幕最下方推出来,并且里面可以带button支持用户点击。它的使用很简单:
Snackbar.make(view, "You Click the Button", Snackbar.LENGTH_LONG).show();
看上面代码几乎可Toast使用一样,上面说了它可以添加button支持点击事件,下面的代码是添加button的:
Snackbar.make(view, "You Click the Button", Snackbar.LENGTH_LONG)
.setAction("返回", new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
})
.show();
这里大家注意一下make方法的第一个参数,它是一个View而不是Context,我们可以理解成这个View是Snackbar的容器,如果此View是CoordinatorLayout,那么Snackbar支持向右滑动删除。
那么是不是Snackbar只能从屏幕底部推出呢?我们看下面部分源码:
private Snackbar(ViewGroup parent) {
mTargetParent = parent;
mContext = parent.getContext();
ThemeUtils.checkAppCompatTheme(mContext);
LayoutInflater inflater = LayoutInflater.from(mContext);
mView = (SnackbarLayout) inflater.inflate(
R.layout.design_layout_snackbar, mTargetParent, false);
}
public static Snackbar make(@NonNull View view, @NonNull CharSequence text,
@Duration int duration) {
<span style="color:#ff0000;">Snackbar snackbar = new Snackbar(findSuitableParent(view));</span>
snackbar.setText(text);
snackbar.setDuration(duration);
return snackbar;
}
private static ViewGroup findSuitableParent(View view) {
ViewGroup fallback = null;
do {
if (view instanceof 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;
}
从上面代码可以看出,如果第一个参数是CoordinatorLayout,那么第一个参数直接为它的父容器,否则的话,它会一直找到这个参数的根容器或者decor content view,也就是说第一个参数传CoordinatorLayout时,它是可以在屏幕任意位置显示的。
还有一个问题,Snackbar中按钮上面的字体颜色可以改变吗?答案是肯定的,它提供了一个方法setActionTextColor(),但是提示文本的颜色就不能修改了,当然你非要改也不是没有办法,毕竟源码都在这里了。
我看网上有人提到,大量使用Snackbar,会导致内存上升,我测试了一下,确实会有这种情况,但我认为正常使用这种情况可以忽略的。首先是每次使用它产生的内存很小,其实这些内存都是可以回收的,系统GC时都可以释放。下面是效果图,demo代码地址: https://github.com/dfqin/MaterialDesignDemo