CoordinatorLayout——小试牛刀

作者: 皮球二二 | 来源:发表于2016-09-18 10:40 被阅读1863次

    在2015年谷歌开发中大会上,谷歌推出了全新的设计语言--Material Design。在发布的众多新控件中,最有意思的一个要数更强大的FrameLayout--CoordinatorLayout。CoordinatorLayout实现了多种Material Design中提到的滚动效果,让你不用写动画代码就能动起来,这些效果包括:

    1. 让FloatingActionButton上下滑动,为Snackbar留出空间。
    2. 扩展、收缩Toolbar或者头部,让主内容区域有更多的空间。
    3. 控制某个view扩展还是收缩,以及其显示大小、比例等,包括视差滚动效果动画。
    4. ......

    来欣赏一下facebook的效果

    facebook

    万变不离其宗,我们从基本入手,一步步来掌握CoordinatorLayout

    初探

    使用CoordinatorLayout需要在Gradle加入Support Design Library:

    compile 'com.android.support:appcompat-v7:24.2.1'
    

    我们来看看最基本的布局效果

    <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <android.support.design.widget.AppBarLayout
            android:id="@+id/main_appbarlayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <android.support.v7.widget.Toolbar xmlns:app="http://schemas.android.com/apk/res-auto"
                android:id="@+id/main_toolbar"
                app:title="@string/app_name"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize">
            </android.support.v7.widget.Toolbar>
        </android.support.design.widget.AppBarLayout>
        <android.support.v4.widget.NestedScrollView xmlns:app="http://schemas.android.com/apk/res-auto"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <LinearLayout
                android:orientation="vertical"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
                    ....
            </LinearLayout>
        </android.support.v4.widget.NestedScrollView>
    </android.support.design.widget.CoordinatorLayout>
    

    这里先不说源码,我直接对布局中一些新概念简单的说明下,

    1. CoordinatorLayout作为最顶层视图,将旗下所有的子view进行调度管理,以达到相互依赖的关系。这个关系是通过Behavior发起的,包括了滑动状态的处理以及View状态(大小、位置等属性)的处理
    2. AppBarLayout其实就是一个垂直的线性布局,跟线性布局相比他实现了很多Material Design效果中Bar的功能,即滑动手势
    3. Behavior是Design库中新诞生的一个布局概念,让你有机会以非侵入式的方式去处理这个View如何和其他View的交互行为。Behavior需要设置在触发事件(比如滚动)的view上,且这个View必须是CoordinatorLayout的第一层级下的子view,否则没有效果,因为Behavior的初始化是在CoordinatorLayout的LayoutParams中通过反射完成的,如果你把值写在LinearLayout中,那么就不行了。
      Behavior实例化既可以像上面提到的用反射将一个类的路径通过app:layout_behavior声明,比如这里appbar_scrolling_view_behavior的值是android.support.design.widget.AppBarLayout$ScrollingViewBehavior,也就是AppBarLayout的内部类ScrollingViewBehavior,同时也可以在你的自定义View类上添加@DefaultBehavior(你的Behavior.class)这句注解,就像AppBarLayout一样
    @CoordinatorLayout.DefaultBehavior(AppBarLayout.Behavior.class)
    
    1. Behavior本身是一个接口而已,调度过程其实是通过NestedScrollingParent与NestedScrollingChild这2个接口完成的,像CoordinatorLayout实现了NestedScrollingParent,RecyclerView或者NestedScrollView实现了NestedScrollingChild接口。有些原生的View好比ListView是没有实现这个接口的,如果想让它拥有滑动嵌套功能,那就必须去设置嵌套滑动条件允许,即设置setNestedScrollingEnabled为true。
      顺带简单说一下流程,因为已经实现了嵌套滚动,所以NestedScrollView的滚动影响着CoordinatorLayout,CoordinatorLayout就会遍历去找所有第一层Behavior。这里找到了AppBarLayout.Behavior,然后AppBarLayout就滚动起来了,顺带着通过appbar_scrolling_view_behavior把NestedScrollView也移动起来
    2. 一般我们看到的文章都是描述CoordinatorLayout跟AppBarLayout还有ViewPager什么的,其实任何View只需使用Behavior配置好关系,都可以在CoordinatorLayout中实现嵌套滚动这个概念,跟AppBarLayout是没有任何关系的
    3. 给大家一个思考题
    xml效果

    看看布局文件的效果,可能你会诧异,为什么NestedScrollView下面会多一块出来?这里面卖一个关子,等我们说到自定义Behavior的时候再来解释

    OK,大致的概念我们介绍完了,run看看。嗯,貌似跟一般线性布局也没啥特别的区别


    初始效果

    等下,好像有点不对劲啊,刚才我们说的滚动功能去哪了?原来还有一个属性 layout_scrollFlags。只要你对AppBarLayout中的子view加这个属性,并且至少包含scroll这个flag,那么他就能滚动起来。否则就像之前那样,一直固定在顶部没啥变化

    app:layout_scrollFlags="scroll"
    
    scroll

    layout_scrollFlags

    AppBarLayout中的子控件通过layout_scrollFlags这个属性或者setScrollFlags才能展现出他们的滚动行为。除了这个scroll以外,还有4个flag,他们分别是snapenterAlwaysenterAlwaysCollapsedexitUntilCollapsed,下面我们分别来举例进行说明

    scroll:所有想滚动的view都需要设置这个flag, 没有设置这个flag的view将被固定在屏幕顶部。这个我们已经见识过了

    snap:这个直接翻译成“折断”没有人能够明白。如果你曾经实现过自定义滑动View的话,这个效果应该很好理解:被"关心"的这个View如果显示了一半,就全显示出来,否则则隐藏。

    app:layout_scrollFlags="scroll|snap"
    
    snap

    enterAlways:往上滑动的时候被"关心"的这个View隐藏,往下滑的时候显示

    app:layout_scrollFlags="scroll|enterAlways"
    
    enterAlways

    enterAlwaysCollapsed:向上滑动的时候被"关心"的这个View隐藏,向下滑动时先展现一个最小高度,等到滑动到NestedScrollView最顶部的时候再完全展现出来

    <android.support.v7.widget.Toolbar xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/main_toolbar"
        app:title="@string/app_name"
        app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"
        android:layout_width="match_parent"
        android:layout_height="200dip"
        android:minHeight="?attr/actionBarSize">
    </android.support.v7.widget.Toolbar>
    

    注意这边一定要有一个最小高度,即minHeight属性,并且enterAlwaysCollapsed一定要搭配enterAlways和scroll才能正常展现

    enterAlwaysCollapsed

    exitUntilCollapsed:向上滚动的时候被"关心"的这个View逐渐折叠到最小高度并固定到顶端

    <android.support.v7.widget.Toolbar xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/main_toolbar"
        app:title="@string/app_name"
        app:layout_scrollFlags="scroll|exitUntilCollapsed"
        android:layout_width="match_parent"
        android:layout_height="200dip"
        android:minHeight="?attr/actionBarSize">
    </android.support.v7.widget.Toolbar>
    

    注意这边也一定要有一个最小高度minHeight,并且exitUntilCollapsed一定要搭配scroll才能正常展现

    exitUntilCollapsed

    这5种flag介绍完毕,最后提醒大家,如果你的AppBarLayout中包含其他的View,那么含有layout_scrollFlags的标签的View请布局在前面。因为AppBarLayout实际上是一个LinearLayout,可以想象一下顺序倒过来是一个什么样的场景,这里我就不多说了

    CollapsingToolbarLayout

    CollapsingToolbarLayout提供了一个可以折叠的Toolbar,它继承FrameLayout。给它设置layout_scrollFlags,它可以控制包含在其中的子控件(如:ImageView、Toolbar),去响应layout_behavior事件发出的相应scrollFlags滚动事件(移除屏幕或固定在屏幕顶端)

    <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <android.support.design.widget.AppBarLayout
            android:id="@+id/main_appbarlayout"
            android:layout_width="match_parent"
            android:layout_height="200dip">
            <android.support.design.widget.CollapsingToolbarLayout xmlns:app="http://schemas.android.com/apk/res-auto"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:expandedTitleMarginStart="64dp"
                app:expandedTitleMarginEnd="64dp"
                app:contentScrim="?attr/colorPrimaryDark"
                app:layout_scrollFlags="scroll|exitUntilCollapsed">
                <ImageView
                    android:src="@mipmap/bg"
                    app:layout_collapseParallaxMultiplier="0.5"
                    app:layout_collapseMode="parallax"
                    android:scaleType="centerCrop"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />
                <android.support.v7.widget.Toolbar
                    app:title="@string/app_name"
                    app:layout_collapseMode="pin"
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize">
                </android.support.v7.widget.Toolbar>
            </android.support.design.widget.CollapsingToolbarLayout>
                </android.support.design.widget.AppBarLayout>
        <android.support.v4.widget.NestedScrollView xmlns:app="http://schemas.android.com/apk/res-auto"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <LinearLayout
                android:orientation="vertical"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
            </LinearLayout>
        </android.support.v4.widget.NestedScrollView>
    </android.support.design.widget.CoordinatorLayout>
    
    CollapsingToolbarLayout

    这里一样简单说明下

    1. layout_collapseMode
      有2种模式,
      pin模式:即固定模式,在折叠的时候最后固定在顶端
      parallax模式:即视差模式,在折叠的时候会有个视差折叠的效果
      我们可以在布局中自己分别设置看看效果
    2. layout_collapseParallaxMultiplier
      CollapsingToolbarLayout滑动时,子视图的视觉差。这个值的范围为0.0-1.0之间。为0的时候,你可以感觉到视图完全随NestedScrollView滚动;为1的时候,似乎又是完全不滚动
    3. contentScrim
      这是ToolBar被折叠到顶部固定后的背景。
    4. expandedTitleMarginStart/expandedTitleMarginEnd
      在ToolBar被折叠前文字部分的左右间距
    5. setExpandedTitleColor/setCollapsedTitleTextColor
      设置还没收缩时状态下字体颜色与收缩后Toolbar上字体的颜色
    6. setTitle
      使用CollapsingToolbarLayout时必须把title设置到CollapsingToolbarLayout上,设置到Toolbar上不会显示

    到此为止,相比大家应该对CoordinatorLayout有了一定的了解,初步使用应该问题不大

    参考文章

    你肯定不晓得的CoordinatorLayout?
    Android5.0+(CollapsingToolbarLayout)

    相关文章

      网友评论

      • 骑小猪看流星:FaceBook效果真心赞 楼主可以写一个Demo 学习下嘛
        皮球二二:@骑小猪看流星 😂
      • 73ece15c815f:请问一下,点击NestedScrollView内的某个按钮,如何把整个NestedScrollView直接自动滑动到顶部,博主能给个思路不呀,想了好几个办法,各种bug。
      • 代码咖啡:您好,请问一下,对于文章里面那个思考题:为什么NestedScrollView下面会多一块出来?不是很理解,想请问一下,如何让NestedScrollView的高度充满剩余的空间而不是高度和屏幕一样宽
        皮球二二:@inerdstack 应该不行吧,我看rv不管设置什么都是match
        代码咖啡:@r17171709 想请问一下,是否可以实现wrap_content的效果,如果不限定死高度的话
        皮球二二:@inerdstack 你将coordinatorLayout不要作为rootview,然后限定死高度
      • xiasuhuei321:最后一张图,可以考虑一下用透明状态栏,今天刚试了一下,被虐了……还没弄好……
        皮球二二:@xiasuhuei321 你可以看看我之前的文章,有专门写沉浸式的
        xiasuhuei321:@r17171709 昨天晚上找了很多文看,发现那个组合起来有设置状态栏的,对这东西还是不熟啊……
        皮球二二:@xiasuhuei321 嗯,我实际项目都是沉浸式的
      • JokAr_:图裂了

      本文标题:CoordinatorLayout——小试牛刀

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