Material Design系列文章(SnakeBar学习笔记)

Material Design系列文章(SnakeBar学习笔记)

1、SnakeBar基本使用

Snackbar.make(activity_main,"今天周五啦!",Snackbar.LENGTH_SHORT)
    .setAction("确定", new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(MainActivity.this,"确定",Toast.LENGTH_SHORT).show();
        }
    }).addCallback(new BaseTransientBottomBar.BaseCallback<Snackbar>() {
        //SnakeBar显示的 时候调用
        @Override
        public void onShown(Snackbar transientBottomBar) {
            super.onShown(transientBottomBar);
        }
        //SnakeBar隐藏的时候调用
        @Override
        public void onDismissed(Snackbar transientBottomBar, int event) {
            super.onDismissed(transientBottomBar, event);
        }
    }).show();

2、SnakeBar可叠加多个Action,但是只对最后一个Action有效

3、可以使用setActionTextColor()方法设置Action文字的的颜色

4、若想修改SnakeBar的文字的样式,则需要通过获取SnakeBar对象,然后获得其对应的TextView(其id为snackbar_text,具体可以看一下源码的xml文件,里面就是一个TextView和一个Button),对其修改部分属性,如:修改文字颜色:

Snackbar bar = Snackbar.make(activity_main,"今天周五啦!",Snackbar.LENGTH_SHORT).setAction("确定", new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(MainActivity.this,"确定",Toast.LENGTH_SHORT).show();
        }
    }).addCallback(new BaseTransientBottomBar.BaseCallback<Snackbar>() {
        //SnakeBar显示的时候调用
        @Override
        public void onShown(Snackbar transientBottomBar) {
            super.onShown(transientBottomBar);
        }
        //SnakeBar小时的时候调用
        @Override
        public void onDismissed(Snackbar transientBottomBar, int event) {
            super.onDismissed(transientBottomBar, event);
        }
    }).setActionTextColor(Color.GREEN);
    ((TextView)(bar.getView().findViewById(R.id.snackbar_text))).setTextColor(Color.YELLOW);
    bar.show();

注意点(踩坑点):

SnakeBar在make方法中的源码如下:

/**
 * Make a Snackbar to display a message
 *
 * <p>Snackbar will try and find a parent view to hold Snackbar's view from the value given
 * to {@code view}. Snackbar will walk up the view tree trying to find a suitable parent,
 * which is defined as a {@link CoordinatorLayout} or the window decor's content view,
 * whichever comes first.
 *
 * <p>Having a {@link CoordinatorLayout} in your view hierarchy allows Snackbar to enable
 * certain features, such as swipe-to-dismiss and automatically moving of widgets like
 * {@link FloatingActionButton}.
 *
 * @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);
    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;
}

其parent为从当前的布局文件中寻找到根布局(为CoordinatorLayout或FragmeLayout),所以当SnakeBar的父控件就是上述两个布局之一时,其显示位置为在父控件的底部,而并不一定在屏幕的底端,除非当其父控件的宽为全屏时,才会得到SnakeBar显示在屏幕底部的效果,具体原因撸波代码即可:

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;
}

从findSuitableParent()方法中可以看到,当前拿到的View为CoordinatorLayout或FragmeLayout时,便结束寻找最终的父控件。