Android之MaterialDesign使用(一)—— 常用控件的基本使用

Google I/O 2014 发布了Material Design。希望统一 Android平台设计语言规范。然而对于国内的很多产品和设计师而言,并没有对此产生多大的兴趣,也许是习惯,也许是觉得android的碎片化太严重不愿意花时间精力去做适配,所以更多的还是采用IOS的风格,导致尽管Material Design推出了很长时间但是在国内使用的还是比较少。但是就风格层面而言,我觉得Material Design所设计的还是非常不错的,特别是很多新推出的控件,使用起来感觉还是挺不错的,因此,还是很有必要学习一下关于Material Design的知识。

Android Material Design新增常用控件

1、ToolBar和Menu配合使用代替ActionBar
2、基于CoordinatorLayout的联动
3、侧滑抽屉NavigationView
4、卡片布局CardView
5、RecyclerView(在本篇里面不介绍,下一篇单独介绍)
6、TabLayout(配合Fragment使用)
7、弹出提醒SnackBar
8、FloatingActionButton

Toobar

toolbar.gif
准备工作

使用Toolbar之前需要引入依赖

implementation 'androidx.appcompat:appcompat:1.3.0'

Toolbar是android 5.0推出的一个新的导航控件用来取代传统的ActionBar控件。需要注意的是,如果使用Toolbar,需要先将系统的ActionBar去掉,可以通过主题将我们的父级主题设置为NoActionBar,如下所示


使用步骤

1、布局里面进行声明


其中 android:theme主题是Toolbar自身的主题,用于显示的样式,那么app:popupTheme主题是干嘛的呢?其实这和后面讲的Menu有关,我们知道ToolBar很多时候是和Menu一起配合使用的,那么app:popupTheme其实就是定义弹出的Menu的样式。

2、代码里面设置Toolbar

setSupportActionBar(toolbar)

由于我们的父级theme已经将actionBar隐藏掉了,所以我们直接设置就行了。

3、通过代码动态设置Toolbar的属性(也可以直接在XML文件里面进行设置)

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

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

/**
 * 创建菜单
 */
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
    menuInflater.inflate(R.menu.designer, menu)
    return true
}

其中designer的布局文件为



    

    

    


在这里面需要重点强调的一点就是showAction属性,它所不同的取值其所代表的意思是:

app:showAsAction="always/ifRoom/never"
always表示永远显示在Toolbar中
ifRoom表示屏幕空间足够的情况下显示在Toolbar中,不够的话就显示在菜单中
never表示永远显示在菜单中

5、监听Menu的点击事件
复写onOptionsItemSelected方法,在这里通过View的ID去执行其所对应的点击事件

/**
 * 响应菜单的点击事件
 */
override fun onOptionsItemSelected(item: MenuItem): Boolean {
    when (item.itemId) {
        R.id.icon_one -> drawer_layout.openDrawer(GravityCompat.START)
        R.id.icon_two -> Toast.makeText(this, "你点击了第二个菜单", Toast.LENGTH_SHORT).show()
        R.id.icon_three -> Toast.makeText(this, "你点击了第三个菜单", Toast.LENGTH_SHORT).show()
    }
    return true
}

基于CoordinatorLayout的联动

CoordinatorLayout的联动算的上是Material Designer的一大亮点,对于CoordinatorLayout来说,其重要的作用就是实现协调其他组件实现联动的效果。


CoordinatorLayout联动.gif

其布局文件为



    

        

            

            

        

    

    

        

            

                

            

        

    


既然是协调其他组件,那么CoordinatorLayout肯定是作为最顶层布局进行放置。至于其他的组件,这里大概介绍一下:

(1)AppBarLayout:一种支持响应滚动手势的app bar布局,AppBarLayout 继承自LinearLayout,布局方向为垂直方向。所以你可以把它当成垂直布局的LinearLayout来使用。AppBarLayout是在LinearLayou上加了一些材料设计的概念,它可以让你定制当某个可滚动View的滚动手势发生变化时,其内部的子View实现何种动作。

(2)CollapsingToolbarLayout:可折叠的Toolbar。

(3)NestedScrollView:支持嵌套滑动的ScrollView。NestedScrollView与 ScrollView的区别就在于 NestedScrollView支持嵌套滑动,无论是作为父控件还是子控件,嵌套滑动都支持,且默认开启。因此,在一些需要支持嵌套滑动的情景中,比如一个 ScrollView内部包裹一个 RecyclerView,那么就会产生滑动冲突,这个问题就需要你自己去解决。而如果使用 NestedScrollView包裹 RecyclerView,嵌套滑动天然支持,你无需做什么就可以实现前面想要实现的功能了。

(4)CardView:卡片布局(下面会讲到)。

那么,CoordinatorLayout到底是如何进行联动的呢,它对其他组件进行联动的依据又是什么呢?答案其实很简单,就是通过layout_scrollFlags。layout_scrollFlags的取值有很多,具体来说:

(1)scroll:Child View 伴随着scrollingView的滚动事件而滚出或滚进屏幕。需要强调的是如果使用了其他值,必定要使用这个值才能起作用(比如你想使用enterAlways,则必须使用scroll,否则enterAlways无效)。

(2)exitUntilCollapsed:当你定义了一个minHeight,这个view将在滚动到达这个最小高度的时候消失。

(3)enterAlways:一旦向上滚动这个view就可见。

(4)enterAlwaysCollapsed:当你定义了一个minHeight,那么view将在到达这个最小高度的时候开始显示,并且从这个时候开始慢慢展开,当滚动到顶部的时候展开完。

当然,对于NestedScrollView控件来说,它必须添加app:layout_behavior="@string/appbar_scrolling_view_behavior”,这个属性用于通知AppBarLayout,NestedScrollView何时发生了滚动事件。

基于上面的例子可以总结出CoordinatorLayout联动的两点规律:

1、父布局肯定是CoordinatorLayout
2、一定会设置app:layout_scrollFlags和app:layout_behavio两个属性。滑动的view官方建议使用NestedScrollView或者RecyclerView。ListView在5.0以下就没有效果了。

侧滑抽屉NavigationView

NavigationView侧滑栏.gif

1.将DrawerLayout作为根布局




    

        

            
        

        

            

        


        

    

    



观察布局文件可知,在DrawerLayout布局下有两个视图,一个就是我们刚刚讲到的CoordinatorLayout,还有一个是NavigationView,那么这个NavigationView是做什么用的呢?
NavigationView是Google在5.0之后推出布局控件,放在DrawerLayout中来使用从而实现侧拉效果。DrawerLayout关键的两行布局代码

app:headerLayout="@layout/nav_header"
app:menu="@menu/nav_menu"

那么这两行是什么意思呢?看下面图就明白了


NavigationView.png

其中headerLayout的布局为



    


    

    


与我们平时写的布局一致。

Menu布局是一个菜单布局



    

        

        
        
        

    


布局设置完成后效果就出来了,手指向右滑动的时候就会把NavigationView所包裹的内容展示出来,当然,你也可以通过代码点击将NavigationView所包裹的内容展示出来。具体的实现为:

// 打开抽屉
drawer_layout.openDrawer(GravityCompat.START)
// 关闭抽屉
nav_view.setNavigationItemSelectedListener {
    drawer_layout.closeDrawers()
    true
}

卡片布局CardView

卡片布局.png

CardView是继承于FrameLayout,用于布局的圆角,阴影等效果的实现,其基本的属性为:

方法 含义
属性 作用
cardElevation 阴影的大小
cardCornerRadius 卡片的圆角大小
contentPadding 卡片内容于边距的间隔

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

TabLayout(配合Fragment使用)

tabLayout.gif

在众多的APP当中,这种效果已经很普遍了,具体来说,就是使用TabLayout + Fragment来实现,其实现的过程为:

1.创建布局文件




    

    

    

2.设置适配器

public class TypeSearchAdapter extends FragmentStatePagerAdapter {

    private FragmentManager mFragmentManager;

    //保存每个Fragment的Tag,刷新页面的依据
    private List fragments;
    private String[] mTitles;

    public TypeSearchAdapter(FragmentManager fm,List fragments, String[] titles) {
        super(fm);
        this.fragments = fragments;
        this.mTitles = titles;
        mFragmentManager = fm;
    }

    @Override
    public Fragment getItem(int position) {
        return fragments.get(position);
    }

    @Override
    public int getCount() {
        return fragments != null ? fragments.size() : 0;
    }

    @Nullable
    @Override
    public CharSequence getPageTitle(int position) {
        return mTitles[position];
    }
}

注意这里使用的是FragmentStatePagerAdapter而非FragmentPagerAdapter。至于为什么,大家可以自行去看看二者的区别在哪。

3.关联

private void init() {
    String[] mTabList = new String[list.size()];
    for (int i = 0; i < list.size(); i++) {
        String title = list.get(i).getTitle();
        mTabList[i] = title;
        mFragmentList.add(TypeSearchDetailAllFragment.newInstance(String.valueOf(list.get(i).getCategoryID()),mTitle,mTitleType));
        if (title.equals(mTitle)) {
            mPosition = i;
        }
    }
    mAdapter = new TypeSearchAdapter(getSupportFragmentManager(), mFragmentList, mTabList);
    mTabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
    mViewPager.setAdapter(mAdapter);
    mTabLayout.setupWithViewPager(mViewPager);
    mViewPager.setCurrentItem(mPosition, false);
    mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

        }

        @Override
        public void onPageSelected(int position) {
            userItem.getMiddleTv().setText(mTabList[position]);
            mTitle = mTabList[position];
        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    });
}

首先实例化好我们需要加载的Fragment,然后通过适配器将它与TabLayout进行关联。这里有两行比较重要的代码

mTabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
mTabLayout.setupWithViewPager(mViewPager);

第一行代码的意思是设置TabLayout的滚动模式,其可选值有两种:
1》TabLayout.MODE_SCROLLABLE:当元素过多时会超出父布局,并可以滑动Tab,Tab的宽度为Tab的实际宽度。
2》TabLayout.MODE_FIXED:无论界面由多少元素都会充满父布局。并且平均分配Tab的宽度。
第二行代码的意思是将TabLayout与ViewPager相关联,因为ViewPager填充的是Fragment,所以相当于TabLayout与Fragment实现了联动,也就是我们上面看到的效果。当然,除此之外,你还可以在布局文件里面设置TabLayout的一些属性,具体的属性为:

方法 含义
tabSelectedTextColor 设置TabLayout选中时候的颜色
tabTextColor 设置TabLayout未选中时候的颜色
tabIndicatorColor 设置TabLayout指示器的颜色
tabBackground 设置TabLayout背景的颜色
tabTextAppearance 设置TabLayout内部字体大小和样式
tabIndicatorHeight 设置TabLayout指示器的高度
tabRippleColor 设置TabLayout条目点击时候的颜色
tabIndicatorFullWidth 设置TabLayout是否填充满整个宽度

弹出提醒Snackbar

Snackbar.gif

Snackbar的使用和Toast基本类似,其基本的使用为:

仅仅只是提示文字弹出提示文字之后一段时间后会消失。

Snackbar.make(button, "第一次使用SnackBar", Snackbar.LENGTH_SHORT).show();

提供一个可以点击的按钮

Snackbar.make(it, "Data deleted", Snackbar.LENGTH_SHORT).setAction(
    "Undo"
) {
    Toast.makeText(this@MaterialDesignerActivity, "Data restored", Toast.LENGTH_SHORT)
        .show()
}.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();

当然,在实际的开发过程中,Snackbar的使用还是比较少的,一般还是更加习惯使用Toast,如果涉及到交互的,很多时候会考虑使用AlertDialog或者PopupWindow而不是Snackbar。

FloatingActionButton

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

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

点击事件监听

 FloatingActionButton fabOne = (FloatingActionButton)findViewById(R.id.fabOne);
 fabOne.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Snackbar.make(v, "FloatingActionButton 被点击", Snackbar.LENGTH_SHORT).show();
            }
  });
至此,Material Design的基本常用控件就结束了,下一篇我们来看看Material Design无比厉害的利器RecyclerView。

你可能感兴趣的:(Android之MaterialDesign使用(一)—— 常用控件的基本使用)