Android CoordinatorLayout实战案例学习《一》

在上篇文章中,和大家一起聊了聊AppBarLayout和CoordinatorLayout两个新控件,以及CoordinatorLayout与FloatingActionButton、Snackbar的使用注意事项。至此,Android Material Design系列的学习已进行到第五篇,大家可以点击以下链接查看之前的文章:

本文继续以案例的形式学习CoordinatorLayout的使用,配合者为AppBarLayout。文中会介绍一些这种搭配使用的案例下可能出现的问题以及解决方案,目的还是一句话,将我所知的分享出来,让正在摸索的你少走一些弯路。老路子,先看一下本文要实现的效果图:

Samples.gif

简单介绍下,这种设计经常会出现在各个app中,作为主页显示,其中主要包含了三个效果:

  • 侧拉导航菜单,这个是用v7包中的控件DrawerLayout实现的,不是本文重点,就不作过多说明了;

  • FAB与Snackbar的协调交互,在上篇文章中已经介绍的很详细了,大家可以另行查看;

  • 列表向上滑动,Toolbar向上隐藏,TabLayout固定于顶部,给内容区域留下更多的展示空间,本文着重讲述这种实现。

知识点比较零碎,还是配合着代码讲解比较容易,思路也会比较清晰一些,主要布局文件的实现:

<?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"
    android:id="@+id/dl_root"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

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

            <include layout="@layout/include_toolbar" />

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

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

        <android.support.v4.view.ViewPager
            android:id="@+id/vp_content"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior" />

        <android.support.design.widget.FloatingActionButton
            android:id="@+id/fab_add"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/dp_16"
            android:onClick="onClickFab"
            android:src="@mipmap/ic_toolbar_add"
            app:backgroundTint="@color/fab_ripple"
            app:layout_anchor="@id/vp_content"
            app:layout_anchorGravity="bottom|right|end" />

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

    <LinearLayout
        android:id="@+id/ll_menu"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:orientation="vertical"
        android:gravity="center"
        android:background="@color/white">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Menu Content"
            android:textColor="@color/black"
            android:textSize="@dimen/sp_16"/>

    </LinearLayout>

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

Android Developer官网中在介绍CoordinatorLayout时有这么一段话:

CoordinatorLayout is intended for two primary use cases:

  1. As a top-level application decor or chrome layout
  2. As a container for a specific interaction with one or more child views

也就是说CoordinatorLayout主要有两种使用场景,在我理解过来就是,作为Activity布局中的最外层容器和作为指定交互行为的多个子控件的父容器来使用。而本文中的案例就属于第二种。

要实现这种滑动交互效果,必须要满足这么几点:

  1. CoordinatorLayout作为容器布局,来协调children view之间的交互行为;

  2. 使用AppBarLayout并设置其内部需要移出屏幕的View的scrollFlags属性,在这个例子中也就是给Toolbar设置。由于Toolbar是通用布局代码,这里我用了include标签,其包含的布局代码为:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/tb_toolbar"
    android:layout_width="match_parent"
    android:layout_height="@dimen/dp_56"
    app:titleTextColor="@color/white"
    app:title="@string/app_name"
    app:theme="@style/OverFlowMenuTheme"
    app:popupTheme="@style/AppTheme"
    android:background="@color/blue"
    app:layout_scrollFlags="scroll|enterAlways"/>

可以看到,我添加了app:layout_scrollFlags这个属性,并将其值设为scroll|enterAlwaysscroll表示滑动型控件向上滑动时toolbar将移出屏幕,enterAlways表示向下滑动时toolbar将重新进入屏幕。由于TabLayout不需要移出屏幕,所以这里就不需要给它设置这个属性了。需要注意的是:不要将app:layout_scrollFlags属性单独设置子include标签里,而是要放在include所加载的layout布局中,否则这个scrollFlags将失去作用,这与include标签的使用有关。

  1. 一个特殊的滑动型控件并设置layout_behavior属性,这里用的是ViewPager。注意,layout_behavior的属性值用的是系统定义好的固定字符串@string/appbar_scrolling_view_behavior,大家感兴趣的自己去翻阅源码看看,后续介绍behavior时,我再仔细讲解。

对于第三点,这里拿出来单独强调一下,有没有发现滑动型控件前我用了“特殊”两个字来修饰!CoordinatorLayout之所以能够协调Children View之间的交互行为,主要就是依赖于NestedScrolling这个东西,这里涉及到两个接口类NestedScrollingParentNestedScrollingChild。CoordinatorLayout实现了前者,而CoordinatorLayout的Children核心之一,滑动型控件,实现了后者,所以才能够做出这个交互行为。关于NestedScrolling,后续再写文单独介绍。所以,这个特殊的滑动型控件必须是实现了NestedScrollingChild接口的控件,比如v7包中的RecyclerView,看一下它的定义就知道了:

public class RecyclerView extends ViewGroup implements ScrollingView, NestedScrollingChild

故,本文中的ViewPager里面的列表控件必须是RecyclerView。如果你仅仅是简单地使用ListView,还是达不到这样的效果。聪明如你,肯定又看出了我的措辞,对的,我又用了一个词:“简单地使用”,那就说明其实稍作处理,复杂点使用,也能够使用ListView的。

在API Level 21及更高版本,为了支持NestedScrolling,所有控件的基类View对外新增了一个方法setNestedScrollingEnabled(boolean enabled),所以,我们可以对ListView稍作处理,就能在Android L及以上版本的系统中使用了:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 
      listView.setNestedScrollingEnabled(true);
}

或者借助 v4 包中的 ViewCompat 类为 ListView 添加设置,避免版本判断:

ViewCompat.setNestedScrollingEnabled(listView, true);

但是,这两种方法均只支持 Android Lollipop 及更高版本,在 pre-lollipop 上是没有效果的。其实,ListView真的已经过气了,我们应该全方位掌握RecyclerView的使用,就像Android Studio取代Eclipse一样。

其他的代码就很简单了,就是给DrawerLayout设置ActionBarDrawerToggle,就是图中ToolBar左侧的菜单按钮。然后用Fragment填充ViewPager,这里就不贴代码了,工程Demo都在GitHub上,大家可以自己下载参考。

其实这个案例的实现还是蛮简单的,文中零零碎碎地讲述了很多使用过程中的细节技巧,帮助大家解决实际问题。下篇文章继续使用案例,介绍CoordinatorLayout的使用方法,同时引入另一个控件的使用,欢迎关注!

示例源码


我在GitHub上建立了一个Repository,用来存放整个Android Material Design系列控件的学习案例,会伴随着文章逐渐更新完善,欢迎大家补充交流,Star地址:

https://github.com/Mike-bel/MDStudySamples

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • 内容抽屉菜单ListViewWebViewSwitchButton按钮点赞按钮进度条TabLayout图标下拉刷新...
    皇小弟阅读 46,416评论 22 663
  • CoordinatorLayout与滚动的处理 CoordinatorLayout实现了多种Material De...
    cxm11阅读 6,524评论 1 15
  • (文/习酒镇•赵半仙) 树叶被施了定身法 停在空中不说话 月亮撇撇嘴 俯视着人间的灯光 有点刺眼睛 星星啊 又偷懒...
    2632385d067a阅读 391评论 3 14
  • 如果二婚和小孩只能选一个, 当然选小孩,小孩是专属资产,老婆是共享资产, 小孩是一种储蓄,老婆是一种消费, 老婆是...
    陈稳阅读 141评论 0 0