AppbarLayout的简单用法

作者: 朋朋彭哥 | 来源:发表于2018-01-20 10:22 被阅读3127次

    在许多App中看到, toolbar有收缩和扩展的效果, 例如:

    appbar.gif
    要实现这样的效果, 需要用到:
    CoordinatorLayoutAppbarLayout的配合, 以及实现了NestedScrollView的布局或控件.
    AppbarLayout是一种支持响应滚动手势的app bar布局, CollapsingToolbarLayout则是专门用来实现子布局内不同元素响应滚动细节的布局.

    与AppbarLayout组合的滚动布局(RecyclerView, NestedScrollView等),需要设置 app:layout_behavior = "@string/appbar_scrolling_view_behavior" .没有设置的话, AppbarLayout将不会响应滚动布局的滚动事件.

    我们回到再前面一章"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"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.truly.mytoolbar.MainActivity">
        <android.support.design.widget.AppBarLayout
            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"
                android:background="?attr/colorPrimary"
               android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
                app:layout_scrollFlags="scroll"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                app:title="Title" />
        </android.support.design.widget.AppBarLayout>
        <android.support.v4.widget.NestedScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">
            <TextView
                android:id="@+id/tv_content"
                android:layout_margin="16dp"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:lineSpacingMultiplier="2"
                android:text="@string/textContent" />
        </android.support.v4.widget.NestedScrollView>
    </android.support.design.widget.CoordinatorLayout>
    

    先看下效果再来解释为什么.


    appbar_2.gif

    可以看到,

    • 随着文本往上滚动, 顶部的toolbar也往上滚动, 直到消失.
    • 随着文本往下滚动, 一直滚到文本的第一行露出来, toolbar也逐渐露出来

    解释:
    从上面的布局中可以看到, 其实在整个父布局CoordinatorLayout下面, 是有2个子布局

    • AppbarLayout
    • NestedScrollView
      NestedScrollView先放一放, 我们来看AppbarLayout.

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

    注意:

    上面提到的"某个可滚动View", 可以理解为某个ScrollView. 就是说,当某个ScrollView发生滚动时,你可以定制你的“顶部栏”应该执行哪些动作(如跟着一起滚动、保持不动等等)。

    这里某个ScrollView就是NestedScrollView或者实现了NestedScrollView机制的其它控件, 如RecyclerView. 它有一个布局行为Layout_Behavior:

    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    

    这是一个系统behavior, 从字面意思就可以看到, 是为appbar设置滚动动作的一个behavior. 没有这个属性的话, Appbar就是死的, 有了它就有了灵魂.

    我们可以通过给Appbar下的子View添加app:layout_scrollFlags来设置各子View执行的动作. scrollFlags可以设置的动作如下:

    (1) scroll: 值设为scroll的View会跟随滚动事件一起发生移动。就是当指定的ScrollView发生滚动时,该View也跟随一起滚动,就好像这个View也是属于这个ScrollView一样。

    上面这个效果就是设置了scroll之后的.

    (2) enterAlways: 值设为enterAlways的View,当任何时候ScrollView往下滚动时,该View会直接往下滚动。而不用考虑ScrollView是否在滚动到最顶部还是哪里.

    我们把layout_scrollFlags改动如下:

    app:layout_scrollFlags="scroll|enterAlways"
    

    效果如下:


    appbar_3.gif

    (3) exitUntilCollapsed:值设为exitUntilCollapsed的View,当这个View要往上逐渐“消逝”时,会一直往上滑动,直到剩下的的高度达到它的最小高度后,再响应ScrollView的内部滑动事件。

    怎么理解呢?简单解释:在ScrollView往上滑动时,首先是View把滑动事件“夺走”,由View去执行滑动,直到滑动最小高度后,把这个滑动事件“还”回去,让ScrollView内部去上滑。

    把属性改下再看效果

    <android.support.v7.widget.Toolbar
        ...
        android:layout_height="?attr/actionBarSize"
        android:minHeight="20dp"
        app:layout_scrollFlags="scroll|exitUntilCollapsed"
    />
    
    appbar_4.gif

    (4) enterAlwaysCollapsed:是enterAlways的附加选项,一般跟enterAlways一起使用,它是指,View在往下“出现”的时候,首先是enterAlways效果,当View的高度达到最小高度时,View就暂时不去往下滚动,直到ScrollView滑动到顶部不再滑动时,View再继续往下滑动,直到滑到View的顶部结束

    这个得把高度加大点才好实验. 来看:

    <android.support.v7.widget.Toolbar
        ...
        android:layout_height="200dp"
        android:minHeight="?attr/actionBarSize"
        app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"
    </android.support.design.widget.AppBarLayout>
    
    appbar_5.gif

    Attention:

    其实toolbar的默认最小高度minHeight就是"?attr/actionBarSize" , 很多时候可以不用设置. 而且从图上可以看出, 其实这里有个缺陷, 就是title的位置和toolbar上的图标行脱离了, 即使在布局里添加了 android:gravity="bottom|start", 在toolbar滚动的时候, title还在, 图标滚动到隐藏了.


    image.png

    后面讲解的CollapsingToolbarLayout可以解决这个问题, 这里先丢出来.

    (5) snap:简单理解,就是Child View滚动比例的一个吸附效果。也就是说,Child View不会存在局部显示的情况,滚动Child View的部分高度,当我们松开手指时,Child View要么向上全部滚出屏幕,要么向下全部滚进屏幕,有点类似ViewPager的左右滑动

    appbar_6.gif

    引入CollapsingToolbarLayout

    CollapsingToolbarLayout是用来对Toolbar进行再次包装的ViewGroup,主要是用于实现折叠(其实就是看起来像伸缩~)的App Bar效果。它需要放在AppBarLayout布局里面,并且作为AppBarLayout的直接子View。CollapsingToolbarLayout主要包括几个功能(参照了官方网站上内容,略加自己的理解进行解释):

    (1) 折叠Title(Collapsing title):当布局内容全部显示出来时,title是最大的,但是随着View逐步移出屏幕顶部,title变得越来越小。你可以通过调用setTitle方法来设置title。

    (2)内容纱布(Content scrim):根据滚动的位置是否到达一个阀值,来决定是否对View“盖上纱布”。可以通过setContentScrim(Drawable)来设置纱布的图片. 默认contentScrim是colorPrimary的色值

    (3)状态栏纱布(Status bar scrim):根据滚动位置是否到达一个阀值决定是否对状态栏“盖上纱布”,你可以通过setStatusBarScrim(Drawable)来设置纱布图片,但是只能在LOLLIPOP设备上面有作用。默认statusBarScrim是colorPrimaryDark的色值.

    (4)视差滚动子View(Parallax scrolling children): 子View可以选择在当前的布局当时是否以“视差”的方式来跟随滚动。(PS:其实就是让这个View的滚动的速度比其他正常滚动的View速度稍微慢一点)。将布局参数app:layout_collapseMode设为parallax

    (5)将子View位置固定(Pinned position children):子View可以选择是否在全局空间上固定位置,这对于Toolbar来说非常有用,因为当布局在移动时,可以将Toolbar固定位置而不受移动的影响。 将app:layout_collapseMode设为pin。

    我们来更改一下布局:

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.design.widget.CoordinatorLayout 
        ...>
    
        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="150dp">
    
            <android.support.design.widget.CollapsingToolbarLayout
                android:id="@+id/collapsing_toolbar_layout"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
                app:layout_scrollFlags="scroll|exitUntilCollapsed">
    
                <android.support.v7.widget.Toolbar
                    android:id="@+id/toolbar"
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize"
                    android:background="?attr/colorPrimary"
                    app:layout_collapseMode="parallax"
                    app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                    app:title="Title" />
            </android.support.design.widget.CollapsingToolbarLayout>
    
        </android.support.design.widget.AppBarLayout>
    
        <android.support.v4.widget.NestedScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">
    
            <TextView
                android:id="@+id/tv_content"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_margin="16dp"
                android:lineSpacingMultiplier="2"
                android:text="@string/textContent" />
        </android.support.v4.widget.NestedScrollView>
    
    </android.support.design.widget.CoordinatorLayout>
    

    可以看到, 我们把原本属于toolbar的几个属性移到了CollapsingToolbarLayout上. 分别是:

    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    app:layout_scrollFlags="scroll|exitUntilCollapsed"
    

    同时给toolbar增加了一个折叠模式属性

    app:layout_collapseMode="parallax"
    

    我们来看下效果:


    appbar_8.gif

    嗯嗯, 折叠模式不对, toolbar的顶部图标没了. 我们改下折叠模式:

    app:layout_collapseMode="pin"
    

    再看效果:


    appbar_9.gif

    我们把scrollFlags属性改下, 看下对比:

    app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"
    
    appbar_10.gif

    效果还是蛮不错的, 有了点Google Material Design的感觉了.

    上面说CollapsingToolbarLayout是个ViewGroup, 那么肯定还可以添加控件. 那么我们在里面添加一个ImageView来看看. 更改布局如下:

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.design.widget.CoordinatorLayout 
        ...>
        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="200dp">
            <android.support.design.widget.CollapsingToolbarLayout
                ...
                android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
                app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed">
                <ImageView
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:scaleType="centerCrop"
                    android:src="@drawable/darkbg"
                    app:layout_collapseMode="parallax" />
                <android.support.v7.widget.Toolbar
                    android:id="@+id/toolbar"
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize"
                    android:background="?attr/colorPrimary"
                    app:layout_collapseMode="pin"
                    app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                    app:title="Title" />
            </android.support.design.widget.CollapsingToolbarLayout>
        </android.support.design.widget.AppBarLayout>
    
        <android.support.v4.widget.NestedScrollView
            ...
            app:layout_behavior="@string/appbar_scrolling_view_behavior">
            <TextView
                ... />
        </android.support.v4.widget.NestedScrollView>
    
    </android.support.design.widget.CoordinatorLayout>
    

    来看下效果:


    appbar_11.gif

    嗯, 有了点意思, 但不美观, 上部的toolbar和图片不协调. toolbar应该有默认的背景属性, 我们去掉它看看.

     <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        app:layout_collapseMode="pin"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
        app:title="Title" />
    

    再看下效果:

    appbar_12.gif

    这次真的不错哦, 已经和很多大公司的app相像了. 但是为什么去掉toolbar的background就可以得到透明背景呢? 说句实话, 没找到原因.

    不过我们没有给CollapsingToolbarLayout设置contentScrim属性哦, 给它加个属性看看.

    <android.support.design.widget.CollapsingToolbarLayout
        ...
        app:contentScrim="?attr/colorPrimary"
        ...>
    
    appbar_13.gif

    嗯嗯, 好像还不如没设置这个属性好呢.

    什么时候需要contentScrim属性呢?
    因为这个布局里面给CollapsingToolbarLayout的layout_scrollFlags设置的是 "scroll|enterAlways|enterAlwaysCollapsed" , toolbar会全部消失的, 所以感觉不是很美观. 如果将layout_scrollFlags属性改为 "scroll|exitUntilCollapsed" , 效果会好点, 适合toolbar还是需要展示的场合.

    appbar_14.gif

    不管怎么样, 先去掉contentScrim属性吧.

    目前有很多APP比较喜欢采用沉浸式设计, 简单点说就是将状态栏和导航栏都设置成透明或半透明的.

    我们来把状态栏statusBar设置成透明. 在style主题中的AppTheme里增加一条:

    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        ...
    
        <item name="android:statusBarColor">@android:color/transparent</item>
    </style>
    

    在布局里面, 将ImageView和所有它上面的父View都添加fitsSystemWindows属性.

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.design.widget.CoordinatorLayout 
        ...
        android:fitsSystemWindows="true">
        <android.support.design.widget.AppBarLayout
            ...
            android:fitsSystemWindows="true">
            <android.support.design.widget.CollapsingToolbarLayout
                ...
                android:fitsSystemWindows="true">
                <ImageView
                    ...
                    android:fitsSystemWindows="true" />
                <android.support.v7.widget.Toolbar
                    ... />
            </android.support.design.widget.CollapsingToolbarLayout>
        </android.support.design.widget.AppBarLayout>
    
    
        <android.support.v4.widget.NestedScrollView
            ...>
            <TextView
                ... />
        </android.support.v4.widget.NestedScrollView>
    
    </android.support.design.widget.CoordinatorLayout>
    

    最后来看下效果:


    appbar_15.gif

    其实还可以在CollapsingToolbarLayout里设置statusBarScrim为透明色, 不过有点问题, 最顶部的toolbar没有完全隐藏, 还留了一点尾巴.


    image.png

    难道就这个属性就没用吗? 我们把layout_scrollFlags改成 "scroll|exitUntilCollapsed" 看看:


    image.png

    这个时候toolbar不用隐藏, 所以还是美美的.

    AppbarLayout整个做成沉浸式之后, 状态栏的图标可能会受到封面图片颜色过浅的影响, 可以给其加一个渐变的不透明层.

    渐变遮罩设置方法:

    在res/drawable文件夹下新建一个名为status_gradient的xml资源文件, 代码如下:

     <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android">
        <gradient
            android:angle="270"
            android:endColor="@android:color/transparent"
            android:startColor="#CC000000" />
            <!-- shape节点中, 可以通过android:shape来设置形状, 默认是矩形.
            gradient节点中angle的值270是从上到下,0是从左到右,90是从下到上。 
            此处的效果就是从下向上, 颜色逐渐由纯透明慢慢变成黑透色-->
    </shape>
    

    布局中, 在ImageView下面增加一个View, 背景设为上面的渐变遮罩.

    <!-- 在顶部增加一个渐变遮罩, 防止出现status bar 状态栏看不清 -->
    <View
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:background="@drawable/status_gradient"
        app:layout_collapseMode="pin"
        android:fitsSystemWindows="true" />
    

    给遮罩设置折叠模式: app:layout_collapseMode="pin" , 折叠到顶部后定住. 来看下效果.

    image.png image.png

    上图是展开状态的对比, 后面的是没有添加遮罩的效果, 前面是添加了遮罩的效果. 下图是添加了遮罩折叠后的效果. 有点黑暗系影片的感觉哦.

    FloatingActionButton再次表演

    作为Google Material Design的一个重要控件, FloatingActionButton怎么可能不在AppbarLayout中起点作用呢. 我们在布局中加一个悬浮按钮, 让它的锚点挂载Appbar的右下角. 这样这个悬浮按钮就和Appbar关联起来了.

    <android.support.design.widget.CoordinatorLayout
        ...>
    
        <android.support.design.widget.AppBarLayout
            ...
        </android.support.design.widget.AppBarLayout>
    
        <android.support.v4.widget.NestedScrollView
        ...
        </android.support.v4.widget.NestedScrollView>
    
        <android.support.design.widget.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="16dp"
            android:src="@drawable/ic_share_white_24dp"
            android:elevation="4dp"
            app:pressedTranslationZ="16dp"
            app:rippleColor="@android:color/white"
            app:layout_anchor="@id/appbar"
            app:layout_anchorGravity="bottom|end"/>
    
    </android.support.design.widget.CoordinatorLayout>
    

    我们来看下效果.

    appbar_16.gif

    好吧, 美美的Toolbar完成了, 有点Google Material Design扑面而来的感觉了.

    这篇文章已经很长了, 还有些内容就不放进来了, 后面陆续完善.

    借鉴了很多资料, 写的时候忘了记录下来, 如对您有损, 请联系我进行删除或更改. 致歉!

    相关文章

      网友评论

        本文标题:AppbarLayout的简单用法

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