美文网首页
打造自己的 APP「冰与火百科」(三):Material Des

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

作者: NanBox | 来源:发表于2017-10-14 10:54 被阅读227次

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

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

    侧滑菜单

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

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

    如果没有选模板,记得在 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 上的按钮联动,像这样:

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

    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 固定模式,完全折叠后固定显示

    效果如下:

    卡片视图

    在 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());
    

    这就是共享元素的效果:

    小结

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

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

    项目地址

    相关文章

      网友评论

          本文标题:打造自己的 APP「冰与火百科」(三):Material Des

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