Android Material Design:常用控件学习笔记

Google I/O 2014 发布了Material Design。希望统一 Android平台设计语言规范。然而再国内的很多产品和设计师并不吃这一套,还是各种仿IOS的UI。作为一个Google粉当然要学会Android Material控件的使用。而且这些控件使用起来非常方便。以下是Android Material常用控件的整理。
请注意:介绍了多个控件、多图预警,流量党珍惜下流量。

介绍的控件:
1、Toolbar和Menu。
2、基于CoordinatorLayout的联动。
3、NavigationView。
4、CardView。
5、TextInputLayout。
6、RecyclerView。
7、TabLayout。
8、SnackBar
9、FloatingActionButton

github地址:https://github.com/AxeChen/MaterialDesignSimple

整理

1、Toolbar

ToolBar是Android 5.0推出的一个新的导航控件用于取代之前的ActionBar。

Toolbar

1.1、基本使用

导入依赖
compile 'com.android.support:appcompat-v7:25.3.1'
修改主题

我们需要使用Toolbar代替Actionbar,就必须将需要使用Toolbar的Activity的Theme设为NoActionBar。

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

由于示例代码中只有一个Activity,所以我将整个AppTheme继承了Theme.AppCompat.Light.NoActionBar。
如果实际情况只有·部分Activity使用Toolbar,可以单独为这些Activity设置没有ActionBar的主题。

布局文件中定义Toolbar

<?xml version="1.0" encoding="utf-8"?>
<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"
    tools:context="com.mg.axe.toolbarsimple.MainActivity">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?android:attr/actionBarSize"
        android:background="@color/colorPrimary"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
        app:theme="@style/ThemeOverlay.AppCompat.ActionBar" />
</RelativeLayout>

setSupportActionBar

这个方法是 AppCompatActivity 中的方法,所以使用的 Activity 必须继承 AppCompatActivity。

   private Toolbar toolbar;
   private void initToolbar() {
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
    }

通过以上三步,Toolbar就能展示了。

1.2、修改toolbar的属性

通过调用Toolbar提供的方法。

可以直接调用Toolbar的一些方法来改变样式:
我写的示例代码中调用的Toolbar方法。

    private void setToolbarProperty() {
        // 设置正标题
        toolbar.setTitle("正标题");
        // 设置副标题
        toolbar.setSubtitle("副标题");
        // 设置左边按钮图片
        toolbar.setNavigationIcon(R.mipmap.ic_launcher_round);
        // 设置(Log)标题与左边按钮之间图标
        toolbar.setLogo(R.mipmap.ic_launcher);
    }

实际上Toolbar提供修改Toolbar属性的方法非常多,远不止以上提供的方法。

在xml文件里修改

先导入命名空间:

 xmlns:app="http://schemas.android.com/apk/res-auto"
在xml文件里修改

属性太多就不整理了。对修改Toolbar的属性,这篇简书整理得不错,可以直接拿来用:http://www.jianshu.com/p/2c21676033db

通过Actionbar来修改

通过Actionbar的一些方法也能够修改Toolbar的一些样式(因为里面用了代理模式,具体还在研究中)。


通过Actionbar来修改

这篇简书也有提到 : http://www.jianshu.com/p/7b5c99e1cfa3
部分方法的作用:http://blog.csdn.net/andygo_520/article/details/51439688

1.3、Toolbar点击的回调

Toolbar的点击回调主要是左边的按钮点击回调和toolbar上面的Menu点击回调。
对于Menu的点击回调更习惯重写onOptionsItemSelected方法来监听回调,后面的Menu会提到。

   // 点击左侧按钮监听
  toolbar.setNavigationOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
          Toast.makeText(MainActivity.this, "点击了Navigation按钮", Toast.LENGTH_SHORT).show();
      }
  });
   // toolbar的Menu回调
  toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
    @Override
    public boolean onMenuItemClick(MenuItem item) {
        return false;
    }
});

1.4、Toolbar添加Menu

Menu是Toolbar非常重要的部分,可以将一些功能放在Menu上来实现,常见的有发送,分享等等。

添加Menu

首先必须在Activity重写onCreateOptionsMenu方法,添加Menu的操作都在这个方法中执行。

@Override
    public boolean onCreateOptionsMenu(Menu menu) { 
            return super.onCreateOptionsMenu(menu);
    }

添加Menu有两种方式:

  • 通过加载Menu资源文件
  • 代码添加

如果通过资源文件添加,先要在res/menu下添加一个menu的资源文件。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/action_settings"
        android:icon="@android:drawable/ic_menu_set_as"
        android:orderInCategory="100"
        android:title="设置"
        app:showAsAction="never" />
    <item
        android:id="@+id/action_share"
        android:icon="@android:drawable/ic_menu_share"
        android:orderInCategory="100"
        android:title="分享"
        app:showAsAction="always" />
    <item
        android:id="@+id/action_edit"
        android:icon="@android:drawable/ic_menu_edit"
        android:orderInCategory="100"
        android:title="编辑"
        app:showAsAction="ifRoom" />
</menu>

如果是通过代码添加,onCreateOptionsMenu方法中调用menu.add()方法。

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        //使用代码创建menu
        //menu.add(0, 0, 0, "搜索").setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
        menu.add(0, 0, 0, "搜索").setIcon(android.support.v7.appcompat.R.drawable.abc_ic_search_api_material).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
        //使用加载xml文件的方式创建
        getMenuInflater().inflate(R.menu.test_menu, menu);
        //添加子菜单
        menu.addSubMenu(0, 1, 0, "submenu").setIcon(R.mipmap.ic_launcher).addSubMenu(0, 2, 0, "submenu1");
        return super.onCreateOptionsMenu(menu);
    }

这里有个重要的属性showAsAction,选项和作用如下:
never:永远不显示的ToolBar上,只放在OverFlow按钮中(最右边三个点的按钮)。只有OverFlow按钮才会弹出。
always :总会展示在Toolbar上。
ifRoom :如Toolbar还有足够的空间,则显示在Toolbar上。否则就放在OverFlow按钮中。
withText,collapseActionView没用过,看下这篇博客的说明吧:http://www.jianshu.com/p/4106e1414d64

3.5、监听Menu点击

首先重写onOptionsItemSelected方法。
根据MenuItem.getItemId()的方法即可找点击的Menu。
如果是加载Menu资源文件,那么ItemId就是给Item设置的id。

 <item
        android:id="@+id/action_settings"
        android:icon="@android:drawable/ic_menu_set_as"
        android:orderInCategory="100"
        android:title="设置"
        app:showAsAction="never" />

如果通过代码添加的Menu,那么ItemId就是调用add方法传入的itemid。看下add方法的源码就可以找到。

public MenuItem add(int groupId, int itemId, int order, CharSequence title);

监听点击的代码。

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case 0:
                Toast.makeText(this, "点击搜索", Toast.LENGTH_SHORT).show();
                break;
            case 1:
                Toast.makeText(this, "点击submenu", Toast.LENGTH_SHORT).show();
                break;
            case 2:
                Toast.makeText(this, "submenu1", Toast.LENGTH_SHORT).show();
                break;
            case R.id.action_settings:
                Toast.makeText(this, "点击设置", Toast.LENGTH_SHORT).show();
                break;
            case R.id.action_edit:
                Toast.makeText(this, "点击编辑", Toast.LENGTH_SHORT).show();
                break;
            case R.id.action_share:
                Toast.makeText(this, "点击分享", Toast.LENGTH_SHORT).show();
                break;
        }
        return super.onOptionsItemSelected(item);
    }

附上Fragment中使用Menu的博客:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2013/0104/777.html

2、基于CoordinatorLayout的联动

CoordinatorLayout是Android Material Design的重要组件,实现协调其他组件实现联动的效果。

2.1、 CollapsingToolbarLayout

效果图:


CollapsingToolbarLayout
添加依赖
 compile 'com.android.support:design:25.3.1'
 compile 'com.android.support:appcompat-v7:25.3.1'
布局结构
<android.support.design.widget.CoordinatorLayout 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:fitsSystemWindows="true"
    tools:context="com.mg.axe.collapsingtoolbarlayout.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar"
        android:layout_width="match_parent"
        android:layout_height="@dimen/app_bar_height"
        android:fitsSystemWindows="true"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/toolbar_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginEnd="64dp"
            app:expandedTitleMarginStart="48dp"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <ImageView
                android:id="@+id/backdrop"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:fitsSystemWindows="true"
                android:scaleType="centerCrop"
                android:src="@mipmap/yangmi"
                app:layout_collapseMode="parallax" />

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/AppTheme.PopupOverlay" />

        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">
    </android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>

既然是基于CoordinatorLayout,所以控件的父布局就是CoordinatorLayout。
重要的属性(这些没有设置是无法实现效果的):

  • CollapsingToolbarLayout中的属性
    app:layout_scrollFlags="scroll|exitUntilCollapsed“
    决定CollapsingToolbarLayout的滑动方式,这些flag的作用:

enterAlways: 一旦向上滚动这个view就可见。
enterAlwaysCollapsed: 当你定义了一个minHeight,那么view将在到达这个最小高度的时候开始显示,并且从这个时候开始慢慢展开,当滚动到顶部的时候展开完。
exitUntilCollapsed: 当你定义了一个minHeight,这个view将在滚动到达这个最小高度的时候消失。

当然这些flag最好是实际使用看效果。

  • NestedScrollView中的属性
    app:layout_behavior="@string/appbar_scrolling_view_behavior”
    这个属性用于通知AppBarLayout 。View(这里是NestedScrollView
    )何时发生了滚动事件。
1.2、向上滑动隐藏Toolbar

效果图:


向上滑动隐藏Toolbar
添加依赖
 compile 'com.android.support:design:25.3.1'
 compile 'com.android.support:appcompat-v7:25.3.1'
布局结构
<android.support.design.widget.CoordinatorLayout 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:fitsSystemWindows="true"
    tools:context="com.mg.axe.coordinatorlayoutscrollsimple.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?android:attr/actionBarSize"
            android:background="@color/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
            app:theme="@style/ThemeOverlay.AppCompat.ActionBar" />

    </android.support.design.widget.AppBarLayout>
 <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">
    </android.support.v4.widget.NestedScrollView>

</android.support.design.widget.CoordinatorLayout>

这里同样需要设置这两个属性:
app:layout_scrollFlags="scroll|enterAlways"
app:layout_behavior="@string/appbar_scrolling_view_behavior"

1.3、其他的一些问题

通过以上的两个例子可以总结出基于CoordinatorLayout联动的两点规律:
1、父布局肯定是CoordinatorLayout
2、一定会设置app:layout_scrollFlagsapp:layout_behavior两个属性。
滑动的View:滑动的view官方建议使用NestedScrollView或者RecyclerView。ListView在5.0以下就没有效果了。
高阶的使用:高阶使用当然是自定义behavior了。http://blog.csdn.net/gdutxiaoxu/article/details/53453958

3、NavigationView

NavigationView用来实现侧滑导航的布局。
效果图:


NavigationView

如果使用Android studio新建Android项目,在选择Activity时会有Navigation Drawer Activity。选择它会生成一个带有侧滑导航栏的Activity。


新建Navigation Drawer Activity
添加依赖
    compile 'com.android.support:appcompat-v7:25.3.1'
    compile 'com.android.support:design:25.3.1'
布局结构
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout 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:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <include
        layout="@layout/app_bar_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/nav_header_main"
        app:menu="@menu/activity_main_drawer" />
</android.support.v4.widget.DrawerLayout>

NavigationView中,主要的两个属性:

 app:headerLayout="@layout/nav_header_main"
 app:menu="@menu/activity_main_drawer" 

如下图所示,NavigationView分为两部分,headerView 和 menu:


QQ截图20170827155506.png

headview:就是普通的布局。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="40dp"
        android:src="@mipmap/ic_launcher_round" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="20dp"
        android:text="AxeChen"
        android:textColor="@android:color/secondary_text_light"
        android:textSize="18sp" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="10dp"
        android:text="不务正业的码农!" />

</LinearLayout>

menu:需要在res/menu下定义:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <group android:checkableBehavior="single">
        <item android:id="@+id/nav_camera" android:icon="@drawable/ic_menu_camera"
            android:title="Import" />
        <item android:id="@+id/nav_gallery" android:icon="@drawable/ic_menu_gallery"
            android:title="Gallery" />
        <item android:id="@+id/nav_slideshow" android:icon="@drawable/ic_menu_slideshow"
            android:title="Slideshow" />
        <item android:id="@+id/nav_manage" android:icon="@drawable/ic_menu_manage"
            android:title="Tools" />
    </group>
    <item android:title="Communicate">
        <menu>
            <item android:id="@+id/nav_share" android:icon="@drawable/ic_menu_share"
                android:title="Share" />
            <item android:id="@+id/nav_send" android:icon="@drawable/ic_menu_send"
                android:title="Send" />
        </menu>
    </item>
</menu>

3.1 修改样式

  • 用代码修改 : NavigationView提供了很多setXXX()的方法。
  • xml文件中修改:
    xml文件中修改

    记得添加命名空间

3.1、其他的问题

menu图片为灰色问题
在使用的时候,会发现所有的图片多会展示成灰色,不管你的图片是否为彩色的图片。
如下方法解决:

NavigationView navigationView = (NavigationView) findViewById(R.id.navigation_view);  
navigationView.setItemIconTintList(null);  

4、CardView

效果图:


CardView

CardView并不属于design包,所以使用CardView必须先添加依赖:

    compile 'com.android.support:cardview-v7:25.3.1'

CardView是一个继承FrameLayout的View。用于布局的圆角、阴影等效果。基本使用只要知道CardView一些常用属性即可。

属性 作用
cardElevation 阴影的大小
cardElevation 阴影最大高度
cardElevation 卡片的背景色
cardCornerRadius 卡片的圆角大小
contentPadding 卡片内容于边距的间隔
contentPaddingBottom 卡片内容与底部的边距
contentPaddingTop 卡片内容与顶部的边距
contentPaddingLeft 卡片内容与左边的边距
contentPaddingRight 卡片内容与右边的边距
contentPaddingStart 卡片内容于边距的间隔起始
contentPaddingEnd 卡片内容于边距的间隔终止
cardUseCompatPadding 设置内边距,V21+的版本和之前的版本仍旧具有一样的计算方式
cardPreventConrerOverlap 在V20和之前的版本中添加内边距,这个属性为了防止内容和边角的重叠

如果直接给CardView添加android:foreground="?attr/selectableItemBackground"就会加上水波纹点击反馈。

** 遇到的问题:**如果你在RecyclerView中使用CardView,如果你用的context是getApplicationContext(),可能会出现展示出夜间模式的效果。我当时使用getApplicationContext()是为了防止内存溢出。具体原因暂时还不清楚。
出现问题的代码。

    public RecommendAdapter(Context context, List<ParkBean> parkBeanList) {
        this.context = context.getApplicationContext();
        this.parkBeanList = parkBeanList;
    }

解决方案:不使用 context.getApplicationContext();

  public RecommendAdapter(Context context, List<ParkBean> parkBeanList) {
        //this.context = context.getApplicationContext();
        this.context = context;
        this.parkBeanList = parkBeanList;
    }

5、TextInputLayout

5.1 基本使用

使用TextInputLayout控件的效果,需要将EditText作为TextInputLayout的子控件使用,而且只能有一个EditText。

添加依赖
  compile 'com.android.support:design:25.3.1'
布局结构
    <android.support.design.widget.TextInputLayout
        android:id="@+id/tilayoutUserName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:layout_marginTop="30dp"
        >
        <EditText
            android:id="@+id/et_name"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:hint="请输入用户名" />
    </android.support.design.widget.TextInputLayout>

效果图:


TextInputLayout
5.2 错误提示

效果图:


验证输入的字符

TextInputLayout提供了非常方便的错误提示:

  • 当需要错误提示时,调用TextInputLayout的setError("错误提示文字")
  • 如果要清空错误提示时,调用TextInputLayout的setError(null)

以效果图中的用户名为例:
实现Editext的addTextChangedListener方法,监听输入字符。然后根据字符判断输入的字符串是否合理。

    private void initListener() {
        edName.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }
            @Override
            public void afterTextChanged(Editable s) {
                checkName(s.toString());
            }
        });
    }

    private void checkName(String s) {
        if (s.length() < 10) {
            nameInput.setError("名字长度太短");
        } else {
            nameInput.setError(null);
        }
    }

6、RecyclerView

RecyclerView是Android程序员必学控件,如果现在还不会RecyclerView就赶紧学起来!
RecyclerView可以实现GirdView,ListView和瀑布流的效果。可以设置滑动的方向。

添加依赖
    compile 'com.android.support:appcompat-v7:25.3.1'
6.1、LayoutManager

决定RecyclerView以一种怎样的形式展示由LayoutManager决定。
设置GridLayoutManager,实现GridView的效果。
设置LinearLayoutManager,实现ListView的效果。
设置StaggeredGridLayoutManager,实现瀑布流的的效果。


LayoutManager

6.2 RecyclerView.Adapter、 RecyclerView.ViewHolder

实现数据的展示需要用到Adapter和ViewHolder

继承RecyclerView.Adapter的Adapter

必须重写的三个方法:
onCreateViewHolder: 创建ViewHolder并返回,负责为给Item创建视图。
onBindViewHolder: 负责将数据绑定到Item的视图上。
getItemCount: 返回总数据条数。

    private class MyAdapter extends RecyclerView.Adapter {
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            return new ItemViewHolder(LayoutInflater.from(RecyclerListViewActivity.this).inflate(R.layout.item_list, parent, false));
        }
        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
            bindItemViewHolder((ItemViewHolder) holder, position);
        }
        @Override
        public int getItemCount() {
            return items.size();
        }
    }
继承RecyclerView.ViewHolder的ViewHolder

和使用Listview的Viewholder差不多。里面是一些初始化控件的操作。

public class ItemViewHolder extends RecyclerView.ViewHolder {

        private ImageView imageView;
        private TextView tvTitle;
        private TextView tvDescription;

        public ItemViewHolder(View itemView) {
            super(itemView);
            imageView = (ImageView) itemView.findViewById(R.id.ivImg);
            tvTitle = (TextView) itemView.findViewById(R.id.tvTitle);
            tvDescription = (TextView) itemView.findViewById(R.id.tvDescription);
        }
}

6.3 实现ListView、Gridview的效果

前面已经提到过设置不同LayoutManager会展示不同的效果。
实现Listview效果:

 recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));

注意:LinearLayoutManager.VERTICAL为垂直滑动,如果设置成LinearLayoutManager.HORIZONTAL则会水平滑动。
效果图:

ListView的效果

实现GridView效果:

recyclerView.setLayoutManager(new GridLayoutManager(this, 3, LinearLayoutManager.VERTICAL, false));
GridView的效果

至于瀑布流,由于平时使用比较少,这里就不做详细的解释了。

7、TabLayout

效果图:


基本的使用
添加依赖
  compile 'com.android.support:design:26.0.0-alpha1'

7.1、如何添加Tab。

添加Tab

从上图可看出,TabLayout提供了addTab()的方法来添加Tab。初始化Tab之后可以调用setXXX()来决定是展示文字、图片或者自定义布局。

7.2、TabMode

TabLayout.MODE_SCROLLABLE:当元素过多时会超出父布局,并可以滑动Tab,Tab的宽度为Tab的实际宽度。
TabLayout.MODE_FIXED:无论界面由多少元素都会充满父布局。并且平均分配Tab的宽度。

7.3、监听Tab的选择状态

tabLayoutOne.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
            }
            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
            }
            @Override
            public void onTabReselected(TabLayout.Tab tab) {
            }
        });

7.4、修改TabLayou的样式

  • 在布局文件中设置
    在使用自定义属性时,记得添加命名空间。

    布局中设置属性

  • 在代码中设置
    调用Tablayout的setXXX()的方法。

  • 在styles中修改
    继承Widget.Design.TabLayout修改TabLayout的样式。
    继承TextAppearance.Design.Tab修改Tab的样式。

<style name="MyCustomTabLayout" parent="Widget.Design.TabLayout">
    <item name="tabMaxWidth">@dimen/tab_max_width</item>
    <item name="tabIndicatorColor">?attr/colorAccent</item>
    <item name="tabIndicatorHeight">2dp</item>
    <item name="tabPaddingStart">12dp</item>
    <item name="tabPaddingEnd">12dp</item>
    <item name="tabBackground">?attr/selectableItemBackground</item>
    <item name="tabTextAppearance">@style/MyCustomTabTextAppearance</item>
    <item name="tabSelectedTextColor">?android:textColorPrimary</item>
</style>
<style name="MyCustomTabTextAppearance" parent="TextAppearance.Design.Tab">
    <item name="android:textSize">14sp</item>
    <item name="android:textColor">?android:textColorSecondary</item>
    <item name="textAllCaps">true</item>
</style>

修改完毕之后记得将styles设置到TabLayout控件上。

7.5、与Viewpager的联动

效果图:

与viewpager的联动

Viewpager+fragment+导航栏的这种UI结构。已经应用得非常广泛了,几乎是随处可见。TabLayout提供了和Viewpager联动方法,实现简单联动的方法也比较简单。
注:这里代码只考虑了Tab展示Text的情况。如果Tab展示的是图片或者自定义View,会稍微麻烦点。

  viewPager.setAdapter(new PagerAdapter(getSupportFragmentManager()));
  tabLayout.setupWithViewPager(viewPager);

viewPager设置完PagerAdapter之后,调用 tabLayout.setupWithViewPager(viewPager);即可。
PagerAdapter重写getPageTitle方法,根据Viewpager页面的position来展示不同Tab的Text。

 @Override
  public CharSequence getPageTitle(int position) {
            return "第" + (position + 1) + "页";
   }

不过这里还是埋了坑,有时候会出现Tab无法展示的情况(写过的都懂)。
这个链接可以解决这个问题:http://blog.csdn.net/sundy_tu/article/details/52682246

8、SnackBar

添加依赖
 compile 'com.android.support:design:26.0.0-alpha1'

效果图:


SnackBar

SnackBar和Toast的用法差不多,都是通过show方法展示。和Toast不同之处是能和用户交互,同时提供了一些展示和消失的回调,修改SnackBar的文字颜色也比较简单。

8.1 SnackBar的基本使用

  • 仅仅只提示文字:
    弹出提示文字之后一段时间后会消失。
Snackbar.make(button, "第一次使用SnackBar", Snackbar.LENGTH_SHORT).show();
  • 提供一个可以点击的按钮:
    添加一个可以点击的按钮。
Snackbar.make(button, "第一次使用SnackBar", Snackbar.LENGTH_SHORT).setAction("确定", new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {

                    }
                }).show();
  • 必须和用户交互之后才消失:
    Snackbar.make()设置时间的参数改为:Snackbar.LENGTH_INDEFINITE。如果不设置这个参数,Snackbar都会在一段时间后消失。
 Snackbar.make(button, "第一次使用SnackBar", Snackbar.LENGTH_INDEFINITE).setAction("确定", new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {

                    }
                }).show();
  • 添加状态回调:
    监听Snackbar的展示和消失。
Snackbar.make(button, "第一次使用SnackBar", Snackbar.LENGTH_INDEFINITE).setAction("确定", new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {

                    }
                }).addCallback(new Snackbar.Callback() {
                    @Override
                    public void onShown(Snackbar sb) {
                        super.onShown(sb);
                        Toast.makeText(MainActivity.this, "弹出了", Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onDismissed(Snackbar transientBottomBar, int event) {
                        super.onDismissed(transientBottomBar, event);
                        Toast.makeText(MainActivity.this, "消失了", Toast.LENGTH_SHORT).show();
                    }
                }).show();

8.2、修改Snackbar的样式

Snackbar只提供了一个修改按钮文字的方法:snackbar.setActionTextColor(Color.GREEN)
如需修改提示文字,背景的颜色等。可以通过snackbar.getView()获取到Snackbar对应的View进行修改。获取到Snackbar的View之后通过findById就能获取其他的一些控件。(Snackbar对应的布局文件在源码中可以找到。)
注意:这种方式还是存在风险。如果哪天Snackbar更新,Snackbar开发者修改了这些控件的Id,那就无法获取了。

 Snackbar snackbar = Snackbar.make(button, "第一次使用SnackBar", Snackbar.LENGTH_INDEFINITE).setAction("确定", new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {

                    }
                });
                snackbar.setActionTextColor(Color.GREEN);

  //修改背景
  snackbar.getView().setBackgroundResource(R.color.colorPrimaryDark);
  /* snackbar 并没有提供修改提示文字颜色的方法。不过可以通过找到
      snackbar的布局design_layout_snackbar_include通过布局可以找到textview的id。
     再通过snackbar.getView().findViewById(R.id.snackbar_text);
   */
  TextView textView = (TextView) snackbar.getView().findViewById(R.id.snackbar_text);
  textView.setTextColor(getResources().getColor(R.color.colorAccent));
  snackbar.show();

9、FloatingActionButton

FloatingActionButton:界面浮动的标签,一般用于页面关键功能入口。FloatingActionButton非常简单,知道了解FloatingActionButton的一些属性和点击回调即可。
效果图:

FloatingActionButton

常用属性:
先加入命名空间!

属性 作用
fabSize 定义FloatingActionButton的大小。auto(大) mini(小) normal(中)
elevation 普通状态下的阴影深度
pressedTranslationZ 按下时的阴影深度
backgroundTint 默认展示的背景颜色
rippleColor 按下时的颜色(5.0以后为水波纹的颜色)
layout_anchor 定位其他控件,和其他控件边界相交
layout_anchorGravity 和layout_anchor属性联用,在其他控件的相对位置
useCompatPadding 设置内边距
borderWidth 边框宽度(使用的比较少,效果也不好看)

点击回调:

 FloatingActionButton fabOne = (FloatingActionButton) findViewById(R.id.fabOne);
 fabOne.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Snackbar.make(v, "正在打开地图", Snackbar.LENGTH_SHORT).show();
            }
  });

最后

感谢各位程序员老爷看完这个又臭又长的博客!
源码地址:https://github.com/AxeChen/MaterialDesignSimple (欢迎star)

推荐阅读更多精彩内容