`

Snackbar替代Toast

 
阅读更多

在谷歌提出 material design 之后,终于推出了 android.support.design 这个官方的material design库,这几天我也简单浏览了下这个库,基本上我们常用的组件都有了,从今天开始,就可以一步步替换掉

以前使用的github上的那些开源控件了,毕竟谷歌出品 才属精品~~另外分析这个design库的源码我认为是非常有意义的,android上的app 在以前各家都有各家的风格,但是在谷歌出了material design这门新的

设计语言以及官方的库以后,相信越来越多的app 会逐步优化自己的ui 来符合官方的标准,学习这个design库的源码可以让我们以后改写自定义控件的时候更加柔韧有余。

首先,来看一下这个官方的介绍。http://www.google.com/design/spec/components/snackbars-toasts.html#

这个文章系统的阐述了 snackbar和toast的区别和正确使用snackbar的方式。

我简单归纳如下:

1.比toast更加好,毕竟snackbar 可以响应点击事件

2.snackbar 同一时间有且只有一个在显示。

3.snackbar 上不要有图标

4.snackbar上action 只能有一个。

5.如果有悬浮按钮 floating action button的话,snackbar 在弹出的时候 不要覆盖这个button.

6.此外我个人认为snackbar 在一定程度上可以替代dialog的某些应用场景。比如以前网络不通的情况下 我们登陆失败,会给一个dialog提示,现在就可以用snackbar 来做这个有action的提示 更加方便快捷。

使用snackbar:

1.导入support design 库 (这一步在以后的design库的 控件文章里都会舍去)

首先找到你app的build gradle文件

Android Support Design 库 之 Snackbar使用及源码分析

然后增加一个compile语句即可

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

Android Support Design 库 之 Snackbar使用及源码分析

2.编写xml文件以及java文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity"
    android:id="@+id/layout">
 
 
    <!-- 因为snackbar 需要有一个父控件所以 我们暂时就用tv 来做他的父控件-->
    <TextView
        android:id="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:layout_centerVertical="true"
        android:gravity="center"
        android:text="Bottom layout" />
 
</RelativeLayout>

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package com.example.burning.myapplication;
 
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
 
 
public class MainActivity extends ActionBarActivity {
 
    private TextView tv;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) this.findViewById(R.id.tv);
        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //这个地方第一个参数    传进去的是tv    但是实际上你无论传进去什么值 snackbar都一定是从屏幕的最底端出现的    原因在源码
                //分析那边可以看到
                Snackbar.make(tv, "connection error", Snackbar.LENGTH_LONG).setAction("retry"new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        tv.setText("aleady click snackbar");
                    }
                }).show();
 
            }
        });
    }
 
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }
 
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
 
        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }
 
        return super.onOptionsItemSelected(item);
    }
}

 

最后我们来看下效果

Android Support Design 库 之 Snackbar使用及源码分析

 

 

 然后我们来看一下 如果和正常的FAB(悬浮按钮)在一起会有什么效果(注意这里的悬浮按钮我们也使用design库里的并不使用github上开源的)

先看一下xml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">
 
 
    <FrameLayout
        android:id="@+id/layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
 
        <android.support.design.widget.FloatingActionButton
            android:id="@+id/btnFloatingAction"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|right"
            android:src="@drawable/ic_plus"
            app:borderWidth="0dp"
            app:fabSize="normal" />
    </FrameLayout>
</RelativeLayout>


activity代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package com.example.burning.myapplication;
 
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
 
 
public class MainActivity extends ActionBarActivity {
 
    private ViewGroup layout;
 
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        layout = (ViewGroup) this.findViewById(R.id.layout);
        layout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Snackbar.make(layout, "connection error", Snackbar.LENGTH_LONG).setAction("retry"new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                    }
                }).show();
 
            }
        });
    }
 
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }
 
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
 
        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }
 
        return super.onOptionsItemSelected(item);
    }
}

 

来看一下运行效果

Android Support Design 库 之 Snackbar使用及源码分析

大家可以看到当我们的snackbar在弹出的时候    会覆盖到我们的FAB,那这体验是非常糟糕的,这里也给出一个完美的解决方案

其实也很简单用一下design库里的layout即可    java代码不需要改变    只要稍微改一下布局文件即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">
 
 
    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
 
        <android.support.design.widget.FloatingActionButton
            android:id="@+id/btnFloatingAction"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|right"
            android:src="@drawable/ic_plus"
            app:borderWidth="0dp"
            app:fabSize="normal" />
    </android.support.design.widget.CoordinatorLayout>
</RelativeLayout>

 

就是换了一个新的layout而已。

来看下运行的效果。

 

 Android Support Design 库 之 Snackbar使用及源码分析

 

当然了 你要改变这个snackbar的背景色也是可以的 只需要

1
2
3
4
5
6
7
8
Snackbar sb=Snackbar.make(layout, "connection error", Snackbar.LENGTH_LONG).setAction("retry"new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                    }
                });
                //红色
                sb.getView().setBackgroundColor(0xfff44336);
                sb.show();


基本的用法 要点就是这些,我们来看一下这个snackbar的源码   看看谷歌官方是如何编写 material design 风格控件的

这里我无法贴上全部源码 因为太多,只挑重要的流程说 可以从make开始。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
//这个地方就是构造函数
    Snackbar(ViewGroup parent) {
        this.mParent = parent;
        this.mContext = parent.getContext();
        LayoutInflater inflater = LayoutInflater.from(this.mContext);
        this.mView = (Snackbar.SnackbarLayout)inflater.inflate(layout.layout_snackbar, this.mParent, false);
    }
 
    //这个地方就是我们调用的make函数 也就是整个类的一个入口 在这里可以看到 我们的代码转入了snackbar的构造函数
    public static Snackbar make(View view, CharSequence text, int duration) {
        //注意看这个地方调用了 findsuitableparent这个函数
        Snackbar snackbar = new Snackbar(findSuitableParent(view));
        snackbar.setText(text);
        snackbar.setDuration(duration);
        return snackbar;
    }
 
    public static Snackbar make(View view, int resId, int duration) {
        return make(view, view.getResources().getText(resId), duration);
    }
 
    //这个函数其实作用就是无论你传进去的是什么view 我最终都会遍历到framlayout为止,因为activity的最外层实际上就是一个framlayout
    //所以你在调用make函数的时候无论传什么值进去 snackabr都会从最底部弹出来 就是因为这个函数做了这样的工作 但是!!!!
                //如果在遍历到最顶部的framlayout之前 遇到了一个framelayout 那么就会从这个framlayout的底部弹出,而不会从屏幕的最下方弹出了。
    //这个地方CoordinatorLayout的优先级比framlayout还要高 所以你如果穿进去的view是CoordinatorLayout的话 这个snackbar 就一定会从
    //CoordinatorLayout 底部弹出了。如果你CoordinatorLayout的最底部恰好在屏幕中间 那么snackbar 就会从屏幕中间弹出  而不会从底部弹出 这一点一定要注意
    @Nullable
    private static ViewGroup findSuitableParent(View view) {
        ViewGroup fallback = null;
 
        do {
            if(view instanceof CoordinatorLayout) {
                return (ViewGroup)view;
            }
 
            if(view instanceof FrameLayout) {
                if(view.getId() == 16908290) {
                    return (ViewGroup)view;
                }
 
                fallback = (ViewGroup)view;
            }
 
            if(view != null) {
                ViewParent parent = view.getParent();
                view = parent instanceof View?(View)parent:null;
            }
        while(view != null);
 
        return fallback;
    }

 

大家可以看一下第六行。实际上这个mView就是一个内部类的对象

1 private final Snackbar.SnackbarLayout mView;

Android Support Design 库 之 Snackbar使用及源码分析

 

然后接着看第六行的xml文件(到这里其实我们也能猜到了 真正自定义view的snackbar是由snackbar的内部类snackbarlayout来完成的)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ Copyright (C) 2015 The Android Open Source Project
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~      http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
-->
 
<!--注意看class那边的写法  那个$就是代表内部类的一个符号 这个技巧 以后我们自己自定义控件的时候也可以学习-->
<view xmlns:android="http://schemas.android.com/apk/res/android"
      class="android.support.design.widget.Snackbar$SnackbarLayout"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_gravity="bottom"
      style="@style/Widget.Design.Snackbar" /><!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/lmp-mr1-supportlib-release/frameworks/support/design/res/layout/layout_snackbar.xml -->

 

继续看下内部类

Android Support Design 库 之 Snackbar使用及源码分析

找到我们真正的snackbar的布局文件 注意这个地方讨巧的使用了merge标签 这是一个比较好的优化xml的 写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ Copyright (C) 2015 The Android Open Source Project
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~      http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
-->
 
<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/snackbar_padding_vertical"
            android:paddingBottom="@dimen/snackbar_padding_vertical"
            android:paddingLeft="@dimen/snackbar_padding_horizontal"
            android:paddingRight="@dimen/snackbar_padding_horizontal"
            android:textAppearance="@style/TextAppearance.Design.Snackbar.Message"
            android:maxLines="@integer/snackbar_text_max_lines"
            android:layout_gravity="center_vertical|left|start"
            android:ellipsize="end"/>
 
    <TextView
            android:id="@+id/snackbar_action"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="@dimen/snackbar_extra_spacing_horizontal"
            android:layout_marginStart="@dimen/snackbar_extra_spacing_horizontal"
            android:layout_gravity="center_vertical|right|end"
            android:background="?attr/selectableItemBackground"
            android:paddingTop="@dimen/snackbar_padding_vertical"
            android:paddingBottom="@dimen/snackbar_padding_vertical"
            android:paddingLeft="@dimen/snackbar_padding_horizontal"
            android:paddingRight="@dimen/snackbar_padding_horizontal"
            android:visibility="gone"
            android:textAppearance="@style/TextAppearance.Design.Snackbar.Action"/>
 
</merge><!-- From: file:/usr/local/google/buildbot/repo_clients/https___googleplex-android.googlesource.com_a_platform_manifest.git/lmp-mr1-supportlib-release/frameworks/support/design/res/layout/layout_snackbar_include.xml -->

 

到这里 主要的snackbar的一个加载流程就分析完毕了,很多诸如动画的代码部分 我就暂时不去分析他了,大家可以自己仔细分析。

另外有心的同学可能发现了这么一个代码

Android Support Design 库 之 Snackbar使用及源码分析

 

实际上Behavior 我个人认为是这次support design库里面最重要的一个东西,以后我会单独出来讲一下。基本上support design包里 每一个控件都有她的身影出没。

分享到:
评论

相关推荐

    Android点击两次退出的Demo

    7. **最佳实践**:虽然这个Demo提供了一个基本的实现方式,但在实际应用中,还可以考虑其他优化措施,如使用Snackbar替代Toast,或者添加一个自定义对话框来更明显地提示用户。 8. **Android Studio调试**:开发者...

    还在使用Toast吗?来使用Snackbar吧

    在Android应用开发中,UI反馈是提升用户体验的关键因素之一。传统的`Toast`组件在很多情况下...在现代Android应用中,使用`Snackbar`替代`Toast`能够更好地遵循Material Design规范,提升应用的整体质感和用户体验。

    Snackbar使用DEMO下载 可修改字体大小,颜色,滑动消失 代替Toast

    Snackbar是Android开发中一个常用的组件,它用于在屏幕底部显示简短的信息,通常用来替代Toast。在本DEMO中, Snackbar的功能得到了进一步扩展,允许用户自定义字体大小和颜色,并且实现了通过向右侧滑动来消失的...

    android中取代toast的消息窗

    相比于Toast,Snackbar提供了更多的交互可能性,如:点击可执行操作、滑动可关闭、以及可以指定持续时间和动作。使用`Snackbar.make()`方法可以创建一个Snackbar,并通过`setText()`和`setAction()`设置内容和操作。...

    Android-Snackbar工具类

     Snackbar在项目中的使用场景越来越多,可全面的替代Toast,比Toast有更好的体验.该工具类可以方便的对Snackbar的样式,显示时间,位置等属性进行设置,方法比较丰富,调用简单,应该可以满足Snackbar绝大部分的使用场景!

    android 解决Toast重复显示问题

    5. **使用Snackbar替代**:对于更复杂的提示需求,可以考虑使用`Snackbar`,它具有更丰富的自定义选项,并且不会重复显示。 通过以上方法,我们可以有效地解决`Toast`在Android应用中重复显示的问题,提高用户体验...

    Toast范例源代码

    在新项目中,通常推荐使用`Snackbar`替代`Toast`。 总结,`Toast`在Android应用中扮演着重要的角色,用于提供非侵入性的信息提示。理解并熟练运用`Toast`,能够提升用户体验。这个“Toast范例源代码”压缩包可能...

    Android Toast

    - 使用`Snackbar`替代`Toast`,`Snackbar`提供更多功能,如动作按钮和更灵活的显示时间。 通过以上讲解,你应该对如何在Android应用中使用`Toast`以及其在数据加载、内容加载和网络图片加载提示中的应用有了清晰的...

    Android应用五种不同的Toast效果_安卓源码.zip

    在Android应用开发中,`Toast`是一个非常常用的组件,它用于显示短暂的提示...在实际项目中,还可以结合`Handler`或者`CountDownTimer`来控制`Toast`的显示时间,或者使用`Snackbar`作为替代,提供更丰富的交互体验。

    自定义Toast

    同时,考虑在适当的情况下使用Snackbar作为替代,因为Snackbar提供了更多的交互功能,如滑动关闭或点击操作。 总结来说,自定义Toast是Android开发中提升应用通知体验的一种手段,通过创建自定义布局并加载到Toast...

    Flashbar::high_voltage:一个高度可定制的,功能强大且易于使用的Android警报库

    它可以用作Snackbar或Toast的替代品,并提供了许多有用的功能和自定义选项供您使用。 它已被100%用Kotlin编写。 :red_heart: 目录 传播一些 :red_heart: 下载 该库在jCenter中可用, jCenter是Android Studio中...

    所有Dialog对话框.zip

    - 对于非模态Dialog,可以考虑使用Snackbar或Toast作为替代,它们不会阻止用户与屏幕其他部分的交互。 - 尽量避免使用ProgressDialog,因为它们会阻塞用户操作,现在更推荐使用ProgressBar。 通过研究“所有...

    Android Support Library 22.2.0

    6. **Snackbar**:类似iOS中的Toast, Snackbar提供了一种在屏幕底部显示简短消息的方式,可以包含一个操作按钮,用于快速反馈或操作。 7. **CollapsingToolbarLayout**:这种布局可以在滚动时折叠或展开,常用于...

    Android 仿QQ微信登录页面源码.rar

    - 应处理各种可能出现的异常情况,如网络错误、服务器错误、登录失败等,并通过`Snackbar`或`Toast`向用户反馈。 8. **源码结构**: - `readme.md`文件通常包含了项目的简介、使用方法和注意事项,是理解项目的...

    DesignSupportLibDemo

    4. **Snackbar**:类似于Toast,但提供了更多交互性, Snackbar用于显示轻量级的反馈信息。在项目中,我们可能会看到如何在用户执行特定操作后展示Snackbar,以及如何添加动作按钮。 5. **TabLayout**:配合...

    CookieBar2:CookieBar2是一个Android库,用于在屏幕顶部或底部显示消息,通知和警报。 敬酒消息的绝佳替代品。 快餐栏通知的理想替代品。 Android讯息再好不过了!

    Cookie栏2 CookieBar是一个轻量级的库,用于在屏幕顶部或底部显示简短消息。 implementation ' org.aviran.cookiebar2:cookiebar2:1.1.4 '屏幕截图 与原始Cookiebar库的主要区别在于: 滑动以关闭已添加。...

    DesignSupportLibrarySample:Android设计支持库示例应用程序

    7. **Snackbar(轻量级提示)**:提供一种简单的方法来显示短暂的通知,用户可以快速响应或忽略,是Toast的替代品。 8. **PagerTitleStrip/PagerTabStrip**:与ViewPager配合,显示页面标题或标签。 9. **...

    android-support-design-library

    5. Snackbar:类似iOS中的Toast,用于短暂显示轻量级的反馈信息,可以包含一个操作按钮,用户可以直接在Snackbars上进行交互。 6. NavigationView:提供了一个侧滑菜单,常用于 drawer layout 中,可以方便地设置...

    LiveSmashBar:一个外观优雅且易于使用的信息库,与 Android 的 LiveData 集成

    直播吧 LiveSmashBar 是 Android 中原生小吃店和吐司的绝佳替代品。 它允许在使用和行为方面进行很大程度的定制和灵活性。 它还支持LiveData ,这对于显示重复消息是有益的,只是单个初始化。 库完全是在Kotlin 中...

Global site tag (gtag.js) - Google Analytics