117

打造自己的 APP「冰与火百科」(三):Material Design 控件

 6 years ago
source link: https://juejin.im/post/59e17cbcf265da431522ef48
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

打造自己的 APP「冰与火百科」(三):Material Design 控件

2017年10月14日 02:58 ·  阅读 3339
打造自己的 APP「冰与火百科」(三):Material Design 控件

自从 Google I/O 2014 发布 Material Design 到现在,这个设计语言已经相当完善了。Material Design 是我最喜欢的一种设计,在项目中,我会尽可能的使用 Material Design 的控件。

下面给大家简单介绍一下「冰与火百科」里面涉及到的 Material Design 控件。

APP 里需要一个切换内容以及设置的地方,使用侧滑菜单是最好的选择。过去我们都是用 SlidingMenu 这样的第三方控件实现侧滑菜单,随着 Design 库的发布,我们有了官方的侧滑菜单。

在 Android Studio 里新建项目的时候,可以直接选择带有侧滑菜单的模板:

89df44a2852cefbfe3cf7225aa87ea68~tplv-t2oaga2asx-zoom-in-crop-mark:3024:0:0:0.awebp

如果没有选模板,记得在 build.gradle 添加设计库的依赖:

compile "com.android.support:design:${SUPPORT_LIB_VERSION}"复制代码

DrawerLayout

我们看一下首页的布局:

<?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>复制代码

DrawerLayout 包含了主视图及侧滑菜单,负责控制侧滑的效果。而 NavigationView 就是我们的侧滑菜单。

如果使用了 ToolBar,并且要实现侧滑菜单的状态和 ToolBar 上的按钮联动,像这样:

9c7267db810890abd9cc22cf89df4068~tplv-t2oaga2asx-zoom-in-crop-mark:3024:0:0:0.awebp

在初始化的时候加入如下代码就可以实现了:

ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
        this,
        drawerLayout,
        toolbar,
        R.string.navigation_drawer_open,
        R.string.navigation_drawer_close);
drawerLayout.addDrawerListener(toggle);
toggle.syncState();复制代码

NavigationView

从 NavigationView 的布局属性可以看出,它由头部 headerLayout 及菜单列表 menu 两部分组成。

头部 headerLayout 就是一个普通布局,通常用渐变色或者图片来作背景,在上面显示程序名或用户信息。

下面的菜单列表,需要引入一个 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">

    <group android:checkableBehavior="single">
        <item
            android:id="@+id/nav_person"
            android:checked="true"
            android:icon="@drawable/menu_person"
            android:title="人物" />
        <item
            android:id="@+id/nav_house"
            android:icon="@drawable/menu_house"
            android:title="家族" />
        <item
            android:id="@+id/nav_history"
            android:icon="@drawable/menu_history"
            android:title="历史" />
        <item
            android:id="@+id/nav_castles"
            android:icon="@drawable/menu_castle"
            android:title="城堡" />
        <item
            android:id="@+id/nav_night"
            android:checkable="false"
            android:icon="@drawable/menu_bulb"
            android:title="夜间模式"
            app:actionLayout="@layout/menu_switch" />
    </group>

</menu>复制代码

前四项是用于切换显示不同类型的单选按钮。

最后一项是夜间模式的切换按钮。它不可点击,并且通过 actionLayout 引入了另一个布局,布局里是一个开关控件 SwitchCompat。

Listener

给 NavigationView 设置监听器,可以实现对侧边栏菜单的点击监听:

navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()) {
            case R.id.nav_person:
                //...
                break;
            case R.id.nav_night:
                boolean isChecked = switchCompat.isChecked();
                switchCompat.setChecked(!isChecked);
                break;
        }
    return true;
    }
});复制代码

顺便说一下这里 switchCompat 的获取:

Menu menu = navigationView.getMenu();
MenuItem nightItem = menu.findItem(R.id.nav_night);
View nightView = MenuItemCompat.getActionView(nightItem);
SwitchCompat switchCompat = (SwitchCompat) nightView.findViewById(R.id.switch_compat);复制代码

侧滑菜单相关代码基本就这些了,看一下最终的实现效果:

标签选项卡

过去要实现顶部标签栏,也是只能依赖第三方库,现在有了 TabLayout,可以很简单就实现这个效果。

布局如下:

<android.support.design.widget.TabLayout
    android:id="@+id/tab_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:tabMode="scrollable"
    app:theme="@style/ThemeOverlay.AppCompat.Dark" />复制代码

设置 tabMode 为 scrollable,让标签栏宽度超过占用的宽度时可以滚动,不然会将所有标签压缩在占用的宽度里。

我们知道选项卡是要和 ViewPager 搭配使用的,在初始化时加一句让它们关联起来就行了:

tabLayout.setupWithViewPager(viewPager)复制代码

这么简单又实现了一个功能:

相信很多人都接触过 PullToRefresh 这样的第三方下拉刷新控件,现在我们来看看 Material Design 的下拉刷新 SwipeRefreshLayout。

在布局里用 SwipeRefreshLayout 包裹要实现下拉刷新的区域,到顶部下拉便会出现加载框,并触发监听器的 onRefresh 方法。我们这样来监听下拉刷新:

swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
    @Override
    public void onRefresh() {
        load();
    }
};复制代码

可以通过 setRefreshing 方法主动开始或停止刷新。

效果如下:

可折叠标题栏

在 APP 里,经常会有一个标题栏,用于显示页面标题、放置搜索或设置按钮。它的作用不言而喻,但在寸土寸金的屏幕里它却一直占据着一块固定的区域。现在,我们能够实现在合适的时候将标题栏折叠起来。下面简单介绍一下涉及到的几个控件。

Toolbar

经过 TitleBar、ActionBar 的发展,现在我们用 Toolbar 来实现标题栏:

<android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"/>复制代码

在代码中初始化:

setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
    // 设置左边按钮可点击
    actionBar.setDisplayHomeAsUpEnabled(true);
}复制代码

AppBarLayout

AppBarLayout 继承自 LinerLayout,支持滑动。要让 Toolbar 响应折叠效果,需要把 AppBarLayout 作为 Toolbar 的父布局。

被 AppBarLayout 包裹的控件,可以设置一个 layout_scrollFlags 属性,即滑动折叠的类型。我给 Toolbar 设置了

app:layout_scrollFlags="scroll|enterAlways"复制代码

代表页面向上、向下滚动时,Toolbar 会跟着一起向上、向下滚动,直到完全隐藏或完全显示。

CoordinatorLayout

单有 AppBarLayout 还不行,还要配合 CoordinatorLayout 使用才能实现折叠效果。CoordinatorLayout 作为一个上层布局,用来协调它的子布局间的交互。

综合上面几个控件,最终布局如下:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:layout_scrollFlags="scroll|enterAlways" />

        <android.support.design.widget.TabLayout
            android:id="@+id/tab_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:tabMode="scrollable"
            app:theme="@style/ThemeOverlay.AppCompat.Dark" />

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

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/swipe_refresh_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <android.support.v4.view.ViewPager
            android:id="@+id/view_pager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

    </android.support.v4.widget.SwipeRefreshLayout>

</android.support.design.widget.CoordinatorLayout>复制代码

要和 Toolbar 实现联动的控件,需要实现了 NestedScrollingChild 接口,并且配置「app:layout_behavior="@string/appbar_scrolling_view_behavior"」。这里常用的控件有 SwipeRefreshLayout、NestedScrollView、RecyclerView。

基本都是布局代码,就可以实现这样的效果:

CollapsingToolbarLayout

除了简单的将 Toolbar 收起,还可以实现将图片收缩转换为 Toolbar 的酷炫效果。要实现这个效果需要使用 CollapsingToolbarLayout,用它包裹 ImageView 和 Toolbar:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="200dp">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <ImageView
                android:id="@+id/image_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                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" />

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

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

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

        <WebView
            android:id="@+id/web_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </android.support.v4.widget.NestedScrollView>

</android.support.design.widget.CoordinatorLayout>复制代码

CollapsingToolbarLayout 内的控件需要设置 layout_collapseMode 属性,可选值有:

  • parallax 视差模式,随着页面滚动会有视差折叠效果
  • pin 固定模式,完全折叠后固定显示

效果如下:

a203d71be6f0e6d5138299e7a8ee3fe6~tplv-t2oaga2asx-zoom-in-crop-mark:3024:0:0:0.awebp

在 Material Design 里有一个概念是「卡片」,而 CardView 就是这个概念的直接体现。

CardView 其实就是一个带有 MD 风格的 FrameLayout,它可以有水波纹点击效果,可以设置圆角、设置 z 轴高度(阴影)。

用的时候记得添加依赖:

compile "com.android.support:cardview-v7:${SUPPORT_LIB_VERSION}"复制代码

用法跟 FrameLayout 是一样的,下面例子设置了水波纹点击效果以及圆角和 z 轴高度:

<android.support.v7.widget.CardView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="10dp"
    android:foreground="?attr/selectableItemBackground"
    app:cardCornerRadius="5dp"
    app:cardElevation="5dp">

    <!--...-->

</android.support.v7.widget.CardView>复制代码

共享元素动画

在 Material Design 里,希望页面的跳转能有一定的连贯性。

如果页面 A 和页面 B 拥有同一个元素,在 Android 5.0 之后,我们可以实现一种叫共享元素的过场动画,这个元素将会从页面 A 的位置,变换到页面 B 的位置。

在「冰与火百科」中,首页列表和详情页都显示了一张人物图片,就可以这样做。

在详情页的 ImageView 配置一个 transitionName,它是元素转换的一个标识:

<ImageView
    android:id="@+id/image_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scaleType="centerCrop"
    android:transitionName="tran_01"/>复制代码

在首页跳转的代码,修改为:

Pair[] pairs = new Pair[]{new Pair(binding.ivImg, "tran_01")};
ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(mainActivity, pairs);
ActivityCompat.startActivity(context, intent, options.toBundle());复制代码

这就是共享元素的效果:

2a2c3fdf0b0f88d3e8be4ab838ba4d46~tplv-t2oaga2asx-zoom-in-crop-mark:3024:0:0:0.awebp

借着写「冰与火百科」,把 Material Design 的部分常用控件归纳了一下。但这里只说了每个控件的基本用法,想有更深入的了解,还需要看查阅相关文章。

我不太懂设计,但有了这些控件,感觉「冰与火百科」还挺好看的~

项目地址


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK