Meterial Design常见控件的使用(三):Snackbar

本文详细解析了Android Material Design中的Snackbar组件,包括其基本使用、源码解析,探讨了Snackbar如何添加到界面、显示位置的修改以及如何管理多个Snackbar的显示。通过对make和show方法的分析,揭示了Snackbar布局的实现细节,并提供了解决问题的思路。
摘要由CSDN通过智能技术生成

引言

2015年5月,Google发布了Design Support Library,添加了很多组件用于支持Material Design。至今过去已经两年了,版本也由当初的22.2.0到现在的26.0.0 Alpha 1。想要了解其中控件的实现原理,当然是从最简单的开始,那就是这篇文章的主角——Snackbar

基本使用

  1. 只有文本提示
Snackbar.make(view, "This is a message", Snackbar.LENGTH_LONG).show();
  1. 有点击按钮
Snackbar.make(view, "This is a message", Snackbar.LENGTH_LONG)
        .setAction("UNDO", new View.OnClickListener() {
   
            @Override
            public void onClick(View v) {
   
                //TODO do something
            }
        })
        .show();

当然还有其他的属性及方法,具体的可参考Google官方文档

带着问题去阅读

  1. Snackbar是如何添加到界面上的?
  2. Snackbar的显示位置如何修改?
  3. Snackbar的布局是否可以修改?
  4. 多个连续的Snackbar是如何管理显示的?
  5. 在CoordinatorLayout中使用FloatingActionButton和SnackBar时,为什么Snackbar不会遮挡FloatingActionButton?

源码解析

源码基于25.3.0
解读源码,应该从什么地方下手呢?当然是从我们使用SnackBar最常用的方法下手了,第一个使用到的那就是make方法了。

make方法

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.");
        }

     ...
      // 后面代码省略
    }

SnackBar中有两个make方法,区别是提示文字传递的类型,一个是CharSequence,一个是Resouse id。传Resouse id最终也会走到上述方法中。
先来看看方法内第一行代码,调用了findSuitableParent(View view)方法,代码如下:

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

代码量不大,而且注释也很清楚。此方法的作用就是循环查找view的上层ViewGroup,直到找到CoordinatorLayout或到根布局结束,返回找到的ViewGroup。
根布局:id为android.R.id.content的布局实际上就是我们setContentView设置自己写的布局的父ViewGroup,类型是FrameLayout,具体的可以去了解DecorView。
再回过头来看看Snackbar的make方法:

public static Snackbar make(@NonNull View view, @NonNull CharSequence text,
         @Duration int duration) {
   
     ....//前面代码省略
     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;
 }

通过inflate获取到SnackBarContentLayout布局,SnackBarContentLayout实际上是一个LinearLayout,再来看看R.layout.design_layout_snackbar_include:

<merge xmlns:android="http://schemas.android.com/apk/res/android">

    <TextView
            android:id="@+id/snackbar_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:paddingTop="@dimen/design_snackbar_padding_vertical"
            android:paddingBottom="@dimen/design_snackbar_padding_vertical"
            android:paddingLeft="@dimen/design_snackbar_padding_horizontal"
            android:paddingRight="@dimen/design_snackbar_padding_horizontal"
            android:textAppearance="@style/TextAppearance.Design.Snackbar.Message"
            android:maxLines="@integer/design_snackbar_text_max_lines"
            android:layout_gravity="center_vertical|left|start"
            android:ellipsize="end"
            android:textAlignment="viewStart"/>

    <Button
            android:id="@+id/snackbar_action"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值