查看原文
其他

用SnackBar替换掉Toast?看完再决定

2017-07-21 承香墨影 承香墨影

版权声明:

本公众号发布的所有文章,未特殊署名,均属于原创,版权归本公众号所有。

转载请参阅公众号的:《转载授权》。

一、前言

Design Support Library 是 Google 发布的一个全新的兼容函数库,它可以在 Android 2.1 (Api level 7)及以上的设备中,实现 Material Design 的效果,这个函数库同时也提供了一系列控件。

今天介绍的 SnackBar 就是其中之一。

在使用 Design Support Library 之前,需要在 build.gradle 文件中,添加依赖。

compile 'com.android.support:design:25.3.0'

二、SnackBar 的常规使用

SnackBar 是一个轻量级的控件,它显示在屏幕的底部,并且在显示和隐藏的时候,带有动画效果。主要用于做一个快速的提示,它可以完美的替代 Toast ,并且在使用的 API 上,也完全和 Toast 的使用方式类似,所以掌握起来,难度并不大。

它和 Toast 最大的不同,是 SnackBar 可以带有一个按钮,也就是说它可以承载简单的交互逻辑。

先来看看 SnackBar 能实现的效果。

可以看到,它会在底部显示一个消息条,并且在显示和隐藏的时候,都是自带动画的,可以承载一个TextView 和 Button。

SnackBar 的 API ,其实很多是参考了 Toast 的,所以他们的使用方式非常的相像。

就拿上面的例子中来看,代码也非常的简单。

SnackBar 之需要传入一个 ViewGroup 然后它就可以在这个 ViewGroup 中显示,通常我们会将这个 ViewGroup 置于屏幕的底部。

SnackBar 是没有 public 的构造方法的,所以需要使用 make() 方法,获取到一个 SnackBar 对象,然后调用 show() 方法,即可显示出来。

在上面的例子中,还使用 setAction() 方法,为其右边的按钮设定文字以及一个点击事件。

下面介绍一下 SnackBar 自带的一些基本 api:

  • make():构造一个 SnackBar 对象,可进行简单配置。

  • show():用于显示一个已经构造好的 SnackBar。

  • setText():为 SnackBar 的设置提示的消息内容。

  • setAction():用于指定右边的按钮显示的文字以及相应的惦记事件。

  • setActionTextColor():设定右边按钮文字的颜色。

  • setCallback():设置 SnackBar 的显示和隐藏时候的回掉监听。

  • setDuration():更新 Duration。

可以看到,SnackBar 本身只提供了非常简单的 API 实现,看来 Google 是指望开发者完全按照他们的风格来设计 App。

三、带着问题来看 SnackBar

前面已经介绍了 SnackBar 的基本 API 的使用,如果想做其他的设置,就需要我们自己进行一些操作了。那么接下来就让我们带着问题来看如何使用 SnackBar 。

下面会涉及到一些 SnackBar 的源码,没兴趣的可以跳过直接看每个问题最后的结论即可。

1、能不能设置一个常驻的 SnackBar

从上面的例子中可以看到,SnackBar 有点模仿 Toast 的意思,给出的两个可供我们选择的值,LENGTH_SHORT 、LENGTH_LONG ,分别表示两个不同显示时间的 SnackBar。

从代码的文档上看,貌似是没有提供给我们用以设定常驻的 SnackBar 的方式。

但是细心看看源码,可以发现,duration,是通过 @Duration 接口限定输入的,而 duration 实际上是有三个取值的,另外一个就是可以设置常驻的。

所以,如果我们有对 SnackBar 有常驻需求的话,可以使用 LENGTH_INDEFINITE 标记即可。

2、去除掉滑动删除功能

前面介绍过,SnackBar 是需要有一个 ViewGroup 容器来容纳它的,而官方推荐使用 CoordinatorLayout 这个 ViewGroup,它实际上也是 Support Design Library 中提供的容器控件。

官方之所以推荐使用它,就是因为它可以让用户通过在 SnackBar 上进行右滑操作,进行删除。

虽然说是这么说,我们还是从源码中看看具体实现。

SnackBar 是继承自 BaseTransientBottomBar 的,而这一段实现正是在父类中。

如图所示,如果 SnackBar 的父布局是 CoordinatorLayout 的话,就使用 Behavior 来实现滑动删除功能。

所以我们如果不需要滑动删除的功能,可以考虑用一个 FrameLayout 来容纳 SnackBar。

或者需要滑动功能,却发现没有实现,检查一下布局,看承载 SnackBar 的容器,是不是 CoordinatorLayout。

3、禁用动画能做到吗?

不知道会不会有一些交互设计师要求不要动画,就这么生硬的显示出来。那么我们来看看到底动画是不是可以被禁用掉。

执行 SnackBar 显示和隐藏动画的逻辑,依然在它的父类BaseTransientBottomBar 中。查看源码可以看到,它在执行显示和隐藏之前,都会调用 shouldAnimate() 方法,来判断是否需要执行一个动画。

这么看,好像 SnackBar 是可以支持关闭动画的,再看看 animateView 的实现。

是否使用动画是依赖 AccessibilityManager 中的 enable 属性决定的,而它是一个私有的属性,并且没有提供修改它的方法,并且如果用反射修改它的值,不确定会不会出现其他的问题,有待验证。

那么可以简单的认为,SnackBar 的动画,是无法简单关闭的。

4、让 SnackBar 显示在顶部可以吗?

既然 SnackBar 是有一个外部容器来承载它的,也就是说,容器在哪里,它实际上就出现在哪里。

所以如果将它置为顶部,其实是可以让它在顶部出现的。但是你以为这样就完了吗?还需要考虑动画的问题,虽然 SnackBar 会出现在顶部,但是动画依然是从下到上出现的,你就会得到一个非常诡异的 SnackBar 。

这明显不是我们想要的。那么是不是想办法改变它出现和隐藏的动画就可以了,继续在源码内找答案。

animateViewIn() 方法就是 SnackBar 显示时候调用的动画,但是实际上,它无法被重写。

所以,将 SnackBar 置于顶部,并且完美的执行动画的设想是达不到的。

5、修改其他的UI样式可以实现吗?

SnackBar 原本提供的可以修改 UI 样式的 API 非常的少,它只能修改右边 Button 字体的颜色。

我们继续在源码内找答案,看看源码可以发现,它的布局是在 SnackBar 中 inflater 出来的。布局文件为,design_layout_snackbar_include.xml

SnackBar 就是用一个 TextView 和一个 Button 实现的。也就是说,我们可以直接找到这两个控件,来改变它的样式。

参考 setText() 方法可以看到,实际上它是通过 mView 对象,拿到一个 SnackbarContentLayout 对象进行操作。mView 这个 View 就是我们需要的。SnackBar 正好也提供了它的 get 方法,所以只需要拿到它,然后对其内的 View 进行样式的修改,即可达到我们的需求。

所以,对于 SnackBar 的样式修改,只要通过 getView() 拿到 mView 对象之后,就可以实现样式的修改了。

四、题外话再说两句

带着问题看源码是一个非常好的读源码的方式。实际上 SnackBar 用起来,看上去非常的好用,但是它封装的东西太多了。如果我们亲爱的设计师能遵照 Material Design 来设计 App,其实直接用 SnackBar 也是一个不错的选择。

对于一些定制要求的类似 SnackBar 的实现。实际上我们已经把 SnackBar 的源码读了一遍了,关键点已经掌握,自己参照 SnackBar 的源码实现一套我们自己的 XxSnackBar 也并不难,都是自己写的代码了,如何实现就看我们自己的了。

我带着的问题,实际上也是我看到 SnackBar 会想到的问题。

推荐阅读:




您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存