引言

文/李牧羊(简书作者)

原文链接:http://www.jianshu.com/p/2654e6bda3b1

著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

在之前我有提到这一篇Android Design Support Library系列文章是关于SnackBar的,但是由于要用到CoordinatorLayout所以先翻译了一篇相关文章,如果还不了解的可以先看一下Android Design Support Library--使用CoordinatorLayout来处理滚动
,这一篇我们讲SnackBar,SnackBar其实就是Toast的升级版,他们之间最大的不同就是:SnackBar会对我们的操作提供一个轻量级的反馈,并且可以对点击事件做出响应,如果是在手机上使用一个SnackBar的话,我们会看到在屏幕底部出现一条简短的信息,如果是在更大的屏幕上这条信息应该会显示在左下角,并且当一个SnackBar显示的时候它是凌驾于当前所有屏幕元素之上的,我们在屏幕上一次只能显示一个SnackBar,如果这么讲不是很清楚的话,我们先来看一个小Demo,通过代码驱动理解是比较好的方式。

示例

根据SnackBar的特点,在屏幕上显示出不同的SnackBar,效果如下:

这里写图片描述

先看一下相关的API文档:

方法类型 方法 作用
void dismiss() 使SnackBar消失
int getDuration() 返回SnackBar的持续时间
View getView() 返回当前SnackBar的View
boolean isShown() 判断该SnackBar是否正在显示
boolean isShownOrQueued() 判断该SnackBar是否正在显示或者排队等待即将要显示
static Snackbar make(View view, int resId, int duration) 新建一个用来显示信息的SnackBar
static Snackbar make(View view, CharSequence text, int duration) 同上
Snackbar setAction(int resId, View.OnClickListener listener) 设置这个即将显示的SnackBar的动作
Snackbar setAction(CharSequence text, View.OnClickListener listener) 同上
Snackbar setActionTextColor(ColorStateList colors) 设置action的文字颜色(右边的)
Snackbar setActionTextColor(int color) 同上
Snackbar setCallback(Snackbar.Callback callback) 设置一个回调,当SnackBar的可见性改变的时候调用
Snackbar setDuration(int duration) 设置SnackBar信息的显示时间
Snackbar setText(int resId) 更新SnackBar上显示的文字
Snackbar setText(CharSequence message) 同上
void show() 显示SnackBar,最后一定要调用这个方法,不然SnackBar不显示,联想Toast

可以看到Demo上显示了三种不同的SnackBar,我们都知道SnackBar是Toast的升级版,但也说明了一个问题那就是SnackBar是用来显示消息的,同时根据你的需求不同可以对这些消息做出一定的响应动作,下面分析三种显示消息方式的不同: - 普通的SnackBar也许有的人并没有过多的需求,只是单纯地想把SnackBar当作一个显示消息的控件而已,那么可以很简单的在代码中这么使用:

Snackbar.make(mCoor, R.string.normal, Snackbar.LENGTH_SHORT).show();

对比一下我们的Toast方式:

Toast.makeText(MainActivity.this,R.string.normal,Toast.LENGTH_SHORT).show();

是不是很像,没错简单的使用的话SnackBar跟Toast并没有多大区别,但是动画效果上是有差异的,如果你注意到了这一点:

这里写图片描述

看,这个侧边滑动消失的效果只有当你使用CoordinatorLayout作为根布局才有,这就是为什么在写SnackBar之前我要先说明一下CoordinatorLayout的原因,如果你使用普通的LinearLayout或者RelativeLayout是不会有这种动画交互效果的,另外,注意SnackBar的make方法有两种重载方法,分别是:

make(View view, int resId, int duration)

make(View view, CharSequence text, int duration)

这里有三个参数,第一个参数View表示的意思是我们传入一个View,然后SnackBar会遍历整个View Tree来找到一个合适的View承载SnackBar的View,如果你想要实现上面的动画交互效果的话最好是传入CoordinatorLayout对象,第二个参数的话是两个重载方法不同的地方,有一种是我们熟知的:

Snackbar.make(mCoor, "普通的SnackBar", Snackbar.LENGTH_SHORT).show();

还有一种要求传入一个ID,注意这个ID并不是指其他的什么,就是你在string.xml文件中定义的字符串资源的ID,比如这样:

Snackbar.make(mCoor, R.string.normal, Snackbar.LENGTH_SHORT).show();

然后第三个参数是SnackBar的持续时间,只有三种:

1、Snackbar.LENGTH_INDEFINITE 一直显示直到另一个SnackBar出现或者主动调用了dismiss()方法
2、Snackbar.LENGTH_SHORT 显示较短的时间
3、Snackbar.LENGTH_LONG 显示较长的时间

但是官方文档是这么描述的:

either be one of the predefined lengths: LENGTH_SHORT, LENGTH_LONG, or a custom duration in milliseconds.

说是可以自定义显示时间,但是我自己试了确实不可以,应该是API文档的一个小bug,如果谁试成功了赶紧告诉我~~如果使用过Toast的话上面的应该很好理解,好了,如果你的业务中对SnackBar并没有更多的要求,那么最普通的SnackBar应该满足了,接下来看稍微高级一点的:

  • 带回调的SnackBar:如果还不太清楚回调的话可以看看这个Android回调函数机制那点事 ,讲这个之前先提一点,如果我们想更加灵活的使用Snackbar的话最好是先持有它的引用,也就是:

    private Snackbar mSnackBar

    原因很简单,你会发现上面提供的常用API中很多方法都是非静态方法并不是静态方法,你要调用的话只能通过SnackBar对象去调用。然后说SnackBar回调之前先说一下Action,SnackBar提供了一个setAction方法:

    1、setAction(int resId, View.OnClickListener listener)
    2、setAction(CharSequence text, View.OnClickListener listener)

    同样是两个重载方法,第一个参数跟前面解释的一样,第二个参数是我们熟知的对点击事件的监听,使用方法如下:

    Snackbar.make(mCoor,R.string.callback,Snackbar.LENGTH_SHORT)
    .setAction(R.string.UNDO, new View.OnClickListener() {
    @Override public void onClick(View v) {
    // do something }
    }).show();

    看一下效果:

    这里写图片描述

    当我们调用了setAction方法并且传入一个字符串之后,SnackBar的右下角就会呈现出我们传入的字符串,并且这个字符串是可点击的,我们可以在点击事件里面做出响应,比如说跳转Activity或者弹出一个Toast等等,这里默认你点击了这个Action这个SnackBar是会消失的。也就是无论你的duration参数设置的是一直显示还是显示多长时间都会消失。有些人可能对右下角这个文字的颜色不满足想要改变,没问题,你想到的Google都给你想好了,SnackBar专门提供了方法来更改Action的文字颜色:

    1、setActionTextColor(ColorStateList colors)
    2、setActionTextColor(int color)

    这里第一种方式不建议用,太复杂,你要想这么用也行:

    Resources resource = (Resources) getBaseContext().getResources();
    ColorStateList csl = (ColorStateList)
    resource.getColorStateList(R.color.PeachPuff);
    mSnackBar.setActionTextColor(csl);

    这是网上找到的一种方式,但是我还是推荐使用第二种方式来更改Action的文字颜色,可以看到是我们熟悉的传入一个int型的值,我提供如下几种方式更改:

1、mSnackBar.setActionTextColor(Color.rgb(232,44,123))
2、mSnackBar.setActionTextColor(Color.BLUE)
3、mSnackBar.setActionTextColor(Color.parseColor("#FFDAB9"));

对了,我还发现一种额外的方式,我们现在使用Android Studio创建新的Project时候系统都会默认在style.xml文件夹下面生成这个:

<style name="AppTheme" parent="The
e.AppCompat.Light.DarkActionBar"> <!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item> </style>

这里的<item name="colorAccent">@color/colorAccent</item>其实也可以更改Action文字颜色,而且默认的Action文字颜色就是这里设置的颜色,但是有一个缺点就是如果你改动了这里,那么很多Material Design控件的相关颜色都会改变,如果你看过我之前写的Android
Design Support Library--TextInputLayout的使用
你会知道TextInputLayout下划线的颜色也是通过这个属性来更改的,所以为了稳定起见还是使用官方提供的方法去更改吧,我这纯属抖个机灵。

那么回到正题,讲讲SnackBar的回调,眼尖的朋友可能发现了,我的Demo里面带回调的SnackBar在弹出和消失的时候都会有Toast通知出现,其实就是使用了SnackBar自带的

setCallback(Snackbar.Callback callback)

方法,这里需要传入一个Snackbar.Callback callback 参数,其实这个,这个Callback 是SnackBar内部的一个抽象类,它内部有两个空实现的方法:

onDismissed(Snackbar snackbar, int event)
onShown(Snackbar snackbar)

顾名思义,我们可以可以分别在这两个方法中定义出当SnackBar消失和产生时我们需要做的事,这两个方法会在SnackBar消失和产生时被回调,打个比方:

mSnackBar.setCallback(new Snackbar.Callback() { @Override public
void onDismissed(Snackbar snackbar, int event) {
super.onDismissed(snackbar, event);
Toast.makeText(MainActivity.this,"SnackBar
Dismiss",Toast.LENGTH_SHORT).show(); } @Override public void
onShown(Snackbar snackbar) { super.onShown(snackbar);
Toast.makeText(MainActivity.this,"SnackBar
Show",Toast.LENGTH_SHORT).show(); } });

这样就实现了在SnackBar消失和产生时弹出Toast通知的动作,其他具体的逻辑可以自己去实现。

完全自定义你自己的SnackBar

如果你对上述使用还是不甚满意,那么接下来我教你怎么自定义你自己的SnackBar,说实话用到的场景并不多,但是学了就学个透彻,这一部分知识的灵感来自于没时间解释了,快使用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);
}

最后一行的inflate是不是很熟悉,我们可不可以认为Snackbar的布局就是这么加载的,这个SnackBarLayout是在SnackBar内部定义的一个继承自LinearLayout的内部类:

public static class SnackbarLayout extends LinearLayout { private
TextView mMessageView; private Button mActionView; private int
mMaxWidth; private int mMaxInlineActionWidth;

看到这几个变量的定义,我已经确定了上面的想法,接下来我们找到上面代码加载的那段布局:

<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="14dp" android:paddingBottom="14dp"
android:paddingLeft="12dp" android:paddingRight="12dp"
android:textAppearance="@style/TextAppearance.Design.Snackbar.
Message" android:maxLines="2"
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="0dp" android:layout_marginStart="0dp"
android:layout_gravity="center_vertical|right|end"
android:paddingTop="14dp" android:paddingBottom="14dp"
android:paddingLeft="12dp" android:paddingRight="12dp"
android:visibility="gone" android:textColor="?attr/colorAccent"
style="?attr/borderlessButtonStyle"/></merge>

看到这两个控件的ID了么

android:id="@+id/snackbar_text"
android:id="@+id/snackbar_action"
public View getView ()Returns the Snackbar's view.

这个方法可以返回我们SnackBar的View,那么这个View是什么,看源码:

那么第一个就是SnackBar左边显示的message,第二个就是我们设置了action时候显示的Button咯,这就简单了,如果你仔细看了上面提供的API文档你会发现有这么一个方法:

/** * Returns the {@link Snackbar}'s view. */
@NonNull public View getView() { return mView; }

找一下mView在哪里定义的:

private final SnackbarLayout mView;mView = (SnackbarLayout)
inflater.inflate( R.layout.design_layout_snackbar, mTargetParent,
false);

好了,这下一切都清楚了,接下里示范一下怎么自定义你自己的SnackBar:

private View view; ....省略中间代码  view =
mCustomSnackBar.getView();
if (view != null) {
view.setBackgroundColor(Color.parseColor("#7B68EE"));
//获取Snackbar的message控件,修改字体颜色
((TextView)view.findViewById(R.id.snackbar_text)).setTextColor(Color.parseColor("#FFDAB9"));
//添加图标
Snackbar.SnackbarLayout snackbarLayout = (Snackbar.SnackbarLayout) view;
//添加自定义布局,这里布局就包含了一个ImageView
//custom_layout是你自定义的布局
View add_view = LayoutInflater.from(view.getContext()).inflate(R.layout.custom_layout
, null);
LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONT
ENT, LinearLayout.LayoutParams.WRAP_CONTENT);
p.gravity = Gravity.CENTER_VERTICAL; //数字表示新加的布局在SnackBar中的位
置,从0开始,取决于你SnackBar里面有多少个子View
snackbarLayout.addView(add_view, 0, p); }

最后一行,addView方法第二个参数表示新加的布局在SnackBar中的位置,注意不要超过总的View的个数不然会报错,message和Action text分别算一个View,其他的话注释已经写得很清楚就不一一解释了,这个代码呈现的效果如下:

这里写图片描述

项目源码

项目GitHub地址

另外,最近做了一个小Demo,主要是使用了ExplosionField 的View爆炸效果,效果图如下:

这里写图片描述

这里写图片描述

有兴趣的可以看看:GitHub地址

文/李牧羊(简书作者)

原文链接:http://www.jianshu.com/p/2654e6bda3b1

著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

安卓高级6 SnackBar的更多相关文章

  1. 安卓高级 WebView的使用到 js交互

    我们先来学习 怎么使用再到用js和安卓源生方法交互 WebView简单使用 此部分转载并做了补充 原博客 原因:比较简单不是很想在写,我只要写js交互部分 WebView可以使得网页轻松的内嵌到app ...

  2. 安卓高级3 Android应用Design Support Library完全使用实例

    原作者:http://www.open-open.com/lib/view/open1433385856119.html 1 背景 上周一年一度的Google IO全球开发者大会刚刚结束,Google ...

  3. 安卓高级9 用原生intent分享

    大家都用过安卓app时发现有个分享按钮如下: 所以今天特此分享用用原生完成: package qianfeng.com.simplesharedemo; import android.content. ...

  4. 安卓高级1 -----Xutil3 和Picasso使用

    Xutils3 Xutils由于内部使用httpclient然而在安卓5.0谷歌发现httpclient出现不稳定的情况.于6.0完全弃用,所以作者升级到Xutils3替换原本网络模块 配置环境(St ...

  5. 【安卓高级】ViewPager视差动画效果

    在安卓开发中,是否遇见过一些很酷的视差动画效果,当ViewPager滑动下一页的时候,页面内的各种元素也能跟随滑动做位移效果,整体看起来非常有活力. 关键的PageTransformer PageTr ...

  6. 安卓高级Fresco图片框架的时候

    Fresco:2015FaceBook推出的 及其强大 支持webp图片格式 和渐进式图片加载 中文文档 使用方法 引入依赖 点击查看具体教程 基本使用步骤 在布局中使用其标签 <com.fac ...

  7. 安卓高级 Android图片缓存之初识Glide

    前言: 前面总结学习了图片的使用以及Lru算法,今天来学习一下比较优秀的图片缓存开源框架.技术本身就要不断的更迭,从最初的自己使用SoftReference实现自己的图片缓存,到后来做电商项目自己的实 ...

  8. 安卓高级EventBus使用详解

    我本来想写但是在网上看了下感觉写得不如此作者写得好:http://www.jianshu.com/p/da9e193e8b03 前言:EventBus出来已经有一段时间了,github上面也有很多开源 ...

  9. 安卓高级 特效动画ExplosionField和 SmoothTransition

    本教程所有图片为github上的所无法正常访问请科学上网 SmoothTransition 展示效果 github:源码地址 使用方法 你能通过一行代码使用上面所有的动画 @Override prot ...

随机推荐

  1. CountDownLatch与thread-join()的区别

    今天学习CountDownLatch这个类,作用感觉和join很像,然后就百度了一下,看了他们之间的区别.所以在此记录一下. 首先来看一下join,在当前线程中,如果调用某个thread的join方法 ...

  2. Testlink1.7.5安装部署

    Testlink1.7.5安装部署 1   下载安装wamp5:下载地址:http://www.duote.com/soft/56016.html wamp5是apache.mysql.PHP的集成环 ...

  3. 再谈前端HTML模板技术

    在web2.0之前,写jsp的时候虽然有es和JSTL,但是还是坚持jsp.后面在外包公司为了快速交货,还是用了php Smart技术. web2.0后,前端模板技术风行. 代表有如下三大类: Str ...

  4. [BZOJ 2654]tree(陈立杰)

    Description 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有need条白色边的生成树. 题目保证有解. Input 第一行V,E,need分别表示点数,边数和需要的白色 ...

  5. [Luogu 3389]【模板】高斯消元法

    Description 给定一个线性方程组,对其求解 Input 第一行,一个正整数 n 第二至 n+1 行,每行 n+1 个整数,为a1,a2⋯an和 b,代表一组方程.1​​,a​2​​⋯a​n​ ...

  6. [AHOI2006]基因匹配

    题目描述 卡卡昨天晚上做梦梦见他和可可来到了另外一个星球,这个星球上生物的DNA序列由无数种碱基排列而成(地球上只有4种),而更奇怪的是,组成DNA序列的每一种碱基在该序列中正好出现5次!这样如果一个 ...

  7. codeforces 868C Qualification Rounds

    Snark and Philip are preparing the problemset for the upcoming pre-qualification round for semi-quar ...

  8. 【luogu P4007 清华集训2017】小Y和恐怖奴隶主

    题目背景 “A fight? Count me in!” 要打架了,算我一个. “Everyone, get in here!” 所有人,都过来! 题目描述 小 Y 是一个喜欢玩游戏的 OIer.一天 ...

  9. poj 1279 半平面交核面积

    Art Gallery Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 6668   Accepted: 2725 Descr ...

  10. hdu 5493 (树状数组)

    题意:在一个队列中,你知道一个人在他左边或者右边比他高的人的个数,求字典序最小的答案 思路:先将人按  矮-->高 排序,然后算出在每个人前面需要预留的位置.树状数组(也可以线段树)解决时,先二 ...