美文网首页控件和规范科技测量
没时间解释了,快使用Snackbar!——Android Sna

没时间解释了,快使用Snackbar!——Android Sna

作者: 简名 | 来源:发表于2016-05-05 00:27 被阅读56725次

    本文是在《Design Support Library第三部分:Snackbar样式》《Snackbar使用及其注意事项》两篇文章的启发下而来,首先对两篇文章的作者表示感谢。

    Snackbar是Android Support Design Library库中的一个控件,可以在屏幕底部快速弹出消息,比Toast更加好用。本文对原生Snackbar进行了修改,使其更加灵活。

    1.Snackbar基本介绍

    使用Snackbar要导入com.android.support:design库。

    Snackbar显示在所有屏幕其它元素之上(屏幕最顶层),同一时间只能显示一个snackbar。

    Snackbar的基本使用很简单,与Toast类似。

    Snackbar.make(view, message_text, duration)
       .setAction(action_text, click_listener)
       .show();
    

    make()方法是生成Snackbar的。Snackbar需要一个控件容器view用来容纳,官方推荐使用CoordinatorLayout来确保Snackbar和其他组件的交互,比如滑动取消Snackbar、Snackbar出现时FloatingActionButton上移。显示时间duration有三种类型LENGTH_SHORT、LENGTH_LONG和LENGTH_INDEFINITE。

    setAction()方法可设置Snackbar右侧按钮,增加进行交互事件。如果不使用setAction()则只显示左侧message。

    Snackbar.make(coordinatorLayout,"这是massage", Snackbar.LENGTH_LONG).setAction("这是action", new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(MainActivity.this,"你点击了action",Toast.LENGTH_SHORT).show();
         }
     }).show();
    

    下面这张图演示了上面代码所实现的效果:Snackbar长显示、点击Action弹出toast提示以及Snackbar在CoordinatorLayout中滑动取消。

    基础演示.gif

    如果你想在Snackbar的显示时或消失时做些什么,可以调用Snackbar的setCallback()方法。

    2.多彩Snackbar

    Snackbar和Toast的默认样式都很单一,但是有时我们希望把不同类型信息区别显示,从而使用户更容易注意到提示信息。所以使Snackbar变色是一个好主意。

    Snackbar的官方API只提供了setActionTextColor()这个方法修改Action的文字颜色,这怎么办?查源码吧,哪里不会点哪里。(><)

    在源码中我们看到Snackbar中定义了一个继承自LinearLayout的内部类SnackbarLayout,Snackbar的样子就是由这个SnackbarLayout实现的。

    SnackbarLayout中加载了R.layout.design_layout_snackbar_include布局文件,打开后看到下面这段代码(我把padding、margin的具体数值也打了出来):

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

    由命名可知,以snackbar_text为名的TextView就是Snackbar左侧的message。

    好了,我们开始修改Snackbar的背景颜色和message字体颜色吧。

    public static void setSnackbarColor(Snackbar snackbar, int messageColor, int backgroundColor) {
        View view = snackbar.getView();//获取Snackbar的view
        if(view!=null){
            view.setBackgroundColor(backgroundColor);//修改view的背景色
            ((TextView) view.findViewById(R.id.snackbar_text)).setTextColor(messageColor);//获取Snackbar的message控件,修改字体颜色
        }
    }
    

    很简单,没有几行代码。

    本文最后提供的Snackbar封装类代码中定义了4种不同类型的信息:Info(妹子向你发来一条消息)、Confirm(妹子已收到你发出的消息)、Warning(妹子删除了你发出的消息)、Alert(妹子已将你拉黑),分别用蓝色、绿色、橙色、红色来表示。

    消息信息.png 警告和错误信息演示.gif

    3.在Snackbar中增加图标

    短文本

    通常 Snackbar 的高度应该仅仅用于容纳所有的文本,而文本应该与执行的操作相关。Snackbar 中不能包含图标,操作只能以文本的形式存在。

    最多0-1个操作,不包含取消按钮

    当一个动作发生的时候,应当符合提示框和可用性规则。当有2个或者2个以上的操作出现时,应该使用提示框而不是 Snackbar,即使其中的一个是取消操作。如果 Snackbar 中提示的操作重要到需要打断屏幕上正在进行的操作,那么理当使用提示框而非 Snackbar。

    上面这段是谷歌 Material Design设计规范中的话。

    但是我就是想在Snackbar中加图标增加趣味性,引起用户注意怎么办?我就是想在Snackbar中放两个按钮进行可选非必要操作怎么办?我就是想整幺蛾子。︿( ̄︶ ̄)︿

    设计规范中的说法是有道理的,因为官方认为“Snackbar是一种针对操作的轻量级反馈机制”,做的麻烦了影响视觉感受。但是对于上述任性的开发者(或者是接了奇葩需求的苦逼开发者)我们也有解决方法。

    前面我们提到过Snackbar的view是由SnackbarLayout实现的,而SnackbarLayout是继承自LinearLayout,那么我们新建一个布局添加进去不就行了么。(~o ̄ ̄)~o...

    public static void SnackbarAddView(Snackbar snackbar,int layoutId,int index) {
        View snackbarview = snackbar.getView();//获取snackbar的View(其实就是SnackbarLayout)
    
        Snackbar.SnackbarLayout snackbarLayout=(Snackbar.SnackbarLayout)snackbarview;//将获取的View转换成SnackbarLayout
    
        View add_view = LayoutInflater.from(snackbarview.getContext()).inflate(layoutId,null);//加载布局文件新建View
    
        LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT);//设置新建布局参数
    
        p.gravity= Gravity.CENTER_VERTICAL;//设置新建布局在Snackbar内垂直居中显示
    
        snackbarLayout.addView(add_view,index,p);//将新建布局添加进snackbarLayout相应位置
    }
    

    上面的代码中,如果我们不设置向Snackbar中添加的布局文件的布局参数,新布局会显示在Snackbar内的顶部。使用上述任性方法的时候要注意新加布局的大小和Snackbar内文字长度,Snackbar过大或过于花哨了可不好看。

    下面是使用示例。我们先新建一个布局,暂时命名为snackbar_addview.xml,简单的放进了一个ImageView,图片就是android默认图标。

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_vertical"
    >
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:src="@mipmap/ic_launcher"/>
    </LinearLayout>
    

    然后在activity中写下snackbar的设置:

     Snackbar snackbar= Snackbar.make(coordinatorLayout,"这是massage", Snackbar.LENGTH_LONG);
    
     SnackbarUtil.setSnackbarColor(snackbar,SnackbarUtil.blue);
    
     SnackbarUtil.SnackbarAddView(snackbar,R.layout.snackbar_addview,0);
    
      snackbar.show();
    
    添加图标演示.gif

    4.SnackbarUtil

    我将我常用的Snackbar相关设置封装成了一个类,大家可以根据自己的需求使用。

    /**
     * Created by 赵晨璞 on 2016/5/1.
     */
    public class SnackbarUtil {
    
    public static final   int Info = 1;
    public static final  int Confirm = 2;
    public static final  int Warning = 3;
    public static final  int Alert = 4;
    
    
    public static  int red = 0xfff44336;
    public static  int green = 0xff4caf50;
    public static  int blue = 0xff2195f3;
    public static  int orange = 0xffffc107;
    
    /**
     * 短显示Snackbar,自定义颜色
     * @param view
     * @param message
     * @param messageColor
     * @param backgroundColor
     * @return
     */
    public static Snackbar ShortSnackbar(View view, String message, int messageColor, int backgroundColor){
        Snackbar snackbar = Snackbar.make(view,message, Snackbar.LENGTH_SHORT);
        setSnackbarColor(snackbar,messageColor,backgroundColor);
        return snackbar;
    }
    
    /**
     * 长显示Snackbar,自定义颜色
     * @param view
     * @param message
     * @param messageColor
     * @param backgroundColor
     * @return
     */
    public static Snackbar LongSnackbar(View view, String message, int messageColor, int backgroundColor){
        Snackbar snackbar = Snackbar.make(view,message, Snackbar.LENGTH_LONG);
        setSnackbarColor(snackbar,messageColor,backgroundColor);
        return snackbar;
    }
    
    /**
     * 自定义时常显示Snackbar,自定义颜色
     * @param view
     * @param message
     * @param messageColor
     * @param backgroundColor
     * @return
     */
    public static Snackbar IndefiniteSnackbar(View view, String message,int duration,int messageColor, int backgroundColor){
        Snackbar snackbar = Snackbar.make(view,message, Snackbar.LENGTH_INDEFINITE).setDuration(duration);
        setSnackbarColor(snackbar,messageColor,backgroundColor);
        return snackbar;
    }
    
    /**
     * 短显示Snackbar,可选预设类型
     * @param view
     * @param message
     * @param type
     * @return
     */
    public static Snackbar ShortSnackbar(View view, String message, int type){
        Snackbar snackbar = Snackbar.make(view,message, Snackbar.LENGTH_SHORT);
        switchType(snackbar,type);
        return snackbar;
    }
    
    /**
     * 长显示Snackbar,可选预设类型
     * @param view
     * @param message
     * @param type
     * @return
     */
    public static Snackbar LongSnackbar(View view, String message,int type){
        Snackbar snackbar = Snackbar.make(view,message, Snackbar.LENGTH_LONG);
        switchType(snackbar,type);
        return snackbar;
    }
    
    /**
     * 自定义时常显示Snackbar,可选预设类型
     * @param view
     * @param message
     * @param type
     * @return
     */
    public static Snackbar IndefiniteSnackbar(View view, String message,int duration,int type){
        Snackbar snackbar = Snackbar.make(view,message, Snackbar.LENGTH_INDEFINITE).setDuration(duration);
        switchType(snackbar,type);
        return snackbar;
    }
    
    //选择预设类型
    private static void switchType(Snackbar snackbar,int type){
        switch (type){
            case Info:
                setSnackbarColor(snackbar,blue);
                break;
            case Confirm:
                setSnackbarColor(snackbar,green);
                break;
            case Warning:
                setSnackbarColor(snackbar,orange);
                break;
            case Alert:
                setSnackbarColor(snackbar,Color.YELLOW,red);
                break;
        }
    }
    
    /**
     * 设置Snackbar背景颜色
     * @param snackbar
     * @param backgroundColor
     */
    public static void setSnackbarColor(Snackbar snackbar, int backgroundColor) {
        View view = snackbar.getView();
        if(view!=null){
            view.setBackgroundColor(backgroundColor);
        }
    }
    
    /**
     * 设置Snackbar文字和背景颜色
     * @param snackbar
     * @param messageColor
     * @param backgroundColor
     */
    public static void setSnackbarColor(Snackbar snackbar, int messageColor, int backgroundColor) {
        View view = snackbar.getView();
        if(view!=null){
            view.setBackgroundColor(backgroundColor);
            ((TextView) view.findViewById(R.id.snackbar_text)).setTextColor(messageColor);
        }
    }
    
    /**
     * 向Snackbar中添加view
     * @param snackbar
     * @param layoutId
     * @param index 新加布局在Snackbar中的位置
     */
    public static void SnackbarAddView( Snackbar snackbar,int layoutId,int index) {
        View snackbarview = snackbar.getView();
        Snackbar.SnackbarLayout snackbarLayout=(Snackbar.SnackbarLayout)snackbarview;
    
        View add_view = LayoutInflater.from(snackbarview.getContext()).inflate(layoutId,null);
    
        LinearLayout.LayoutParams p = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT);
        p.gravity= Gravity.CENTER_VERTICAL;
    
        snackbarLayout.addView(add_view,index,p);
    }
    
    }
    

    简单的使用示例:

    SnackbarUtil.ShortSnackbar(coordinator,"妹子向你发来一条消息",SnackbarUtil.Info).show();
    
    消息演示.gif

    整出幺蛾子的使用示例:

     Snackbar snackbar= SnackbarUtil.ShortSnackbar(coordinator,"妹子删了你发出的消息",SnackbarUtil.Warning).setActionTextColor(Color.RED).setAction("再次发送", new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            SnackbarUtil.LongSnackbar(coordinator,"妹子已将你拉黑",SnackbarUtil.Alert).setActionTextColor(Color.WHITE).show();
        }
     });
    
     SnackbarUtil.SnackbarAddView(snackbar,R.layout.snackbar_addview,0);
    
     SnackbarUtil.SnackbarAddView(snackbar,R.layout.snackbar_addview2,2);
    
      snackbar.show();
    

    这个示例中调用了两次SnackbarAddView()方法向Snackbar中添加了两个不同的自定义布局,效果如下(不建议大家这么玩 _(:з」∠)_ ):

    添加多布局.gif

    暂时就是这些。[]( ̄ ̄)*


    关于Toast的花式使用请看我写的Android Toast花式使用

    相关文章

      网友评论

      • 窝棚:上了大佬的敞篷车:sunglasses:
      • Wyxxs:换背景色的那个差点笑喷😂
      • 212c67d881aa:没有从顶部弹出的吗?
      • RamboPan:为什么我用了,只有背景颜色,文字颜色仿佛被覆盖了?
      • RamboPan:博主太幽默了,内容也是简单易懂,循序渐进,必须赞一个。:wink:
      • fe7af21c74e8:那么问题来了,为毛我加图标后,图标和文字重叠在一起呢,复制你的代码还是一样
      • 絆仙:老司机,能问一下你导入的是哪个版本?
      • 全校最帅的人:不能指定显示位置感觉不大爽啊
      • 37c7796cd658:我一直在用Toast:joy: 前年 用了一个开源控件,里面有看到这个控件,但是一直没用,各种自己作啊,,简单的 直接用Toast给个提示,复杂的就自定义弹窗,慢慢的竟然写了一个自定义弹窗类,里面有各种样式的弹窗,就没在考虑Snackbar,,话说 我都没用过CoordinatorLayout:cry: ,,还是感谢分享
      • f875cc4fb656:害我高了半天,这个东西没什么卵用。
      • 青小葵:这个小可爱可以显示在屏幕顶部吗?下面的元素一定要移动吗?
      • 噗噗bang:微微又硬,表示尊敬
      • 威威猫Alter:最后一张可以可以:smile:
      • 梦想编织者灬小楠:最新的SnackbarLayout已经不继承自LinearLayout了,而是继承自SnackbarBaseLayout,而SnackbarBaseLayout继承自FrameLayout...
        最后的添加自定义布局的方法需要调整了:sweat_smile:
      • Clendy:我擦 必须顶起呀~~
      • 295322880cda:有没有办法自定义SnackBar的弹出位置
        断金岁月:@295322880cda 我也想这么问 你的解决了没有
      • BDwuzhou:添加的View如何获得点击事件呢
      • d07e1834a502:前段时间看了,忘记了,现在再次回味,直接上项目,很感谢哦
      • 冰之月:写得真心不错
      • Maxoxo:有料,写得很详细,赞赞赞👍
      • 69edf3facddb:挺喜欢你的风格,风趣又能让人学到很多东西,加油↖(^ω^)↗ :clap:
      • 幻海流心:楼主,我也写了一个Snackbar的工具类,传到了Github上,功能更丰富一些,欢迎提BUG.
        https://github.com/HuanHaiLiuXin/SnackbarUtils
      • 幻海流心:写的漂亮,调用方式也很方便
      • MeloDev:设置背景颜色的时候出了问题,我设置的是白色,但是显示的是紫色,什么鬼。。
        ae2cb3cbfdc1:getResources().getColor(R.color.white) 这样写就没问题
      • f9963c6b1792:不错😀😀😀😀
      • 相互交流: Snackbar.make(v, R.string.deving, Snackbar.LENGTH_LONG) ;V可以界面中的任何一个View,,不会有什么影响吧??楼主
      • 98f21096254d:添加图片的时候有内存溢出的情况么
      • wulei2554:顶一个,棒棒哒!
      • 七岁小猫:登录就是为了顶你
      • 小胖0_0:好东西,学习了
      • 68858b606c6c:可以,上次写项目就用到了这个。
      • 084914dc3ae1:好棒啊,赶紧抄走 :grin:
      • 幸福就是不断的经历:放在4.2.2的平板上运行.snackbar的宽度不是铺满底部,只会显示在中间一部分啊,是不是啊
      • 9efe1db2c646:写得很好正需要用到,以资鼓励 :smile:
      • 妙法莲花1234:view 可设置为getWindow().getDecorView()
      • Karma1026:喜欢,请问你那个演示动画gif是用什么软件录制的?
        47806e86e1bd:@王小賢 问了我想问的问题 :scream:
        Karma1026:好的,谢谢!
        简名:@王小賢 一个叫GifCam的软件
      • Wastrel:mark
      • fbd7d5eb43a8:很详细啊。
      • 606fd5f5448c:棒棒哒
      • RobinLi:这难到还不评论吗,你在等啥。。。
      • 84bf95ab9e56:微微一硬.略表敬意 :wink:
      • biubiutoo::smirk:也是个逗比
      • 明月几时有__:鸿洋?
        简名:@陆叔叔 对,这篇是我投稿到鸿洋大神公众号的
      • 人间入画:有料。竟然没人评论,沙发
        简名:@人间入画 谢谢捧场~

      本文标题:没时间解释了,快使用Snackbar!——Android Sna

      本文链接:https://www.haomeiwen.com/subject/hdcdrttx.html