美文网首页J2EE|AndroidAndroid-UI界面Material Design
Android Material Design:常用控件学习笔记

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

作者: AxeChen | 来源:发表于2017-08-28 08:41 被阅读963次

    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)

    相关文章

      网友评论

      本文标题:Android Material Design:常用控件学习笔记

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