Android Support Design 之 CoordinatorLayout

当我们使用 Android Studio 的时候 ,是不是会发现有这样一个模块

这个 Basic Activity 中使用的是 CoordinatorLayout 、AppbarLayout、FloatingActionButton 等等的一些控件 。

当我第一眼看见这些新东西的时候 ,第一感觉是,为啥一哈子出来这么多新玩意 ,感觉一时间接受不了。 

但是呢,存在必有它的道理 ,所以今天从 CoordinatorLayout 开始 ,对这些控件作一些简单的介绍。可能写的不全面,但是后续还会继续探讨这个课题。

说了这么多(废话),CoordiantorLayout 字面上看就是协调布局,确实 ,它用来协调 child view 的一些交互 ,下面我们通过代码来看一些装B如风的效果。

CoordinatorLayout & FloatingActionButton

    把FloatingActionButton 放到 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:id="@+id/test_coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/test_recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
 
<android.support.design.widget.FloatingActionButton
android:id="@+id/test_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16sp"
android:src="@mipmap/ic_done"
app:layout_anchor="@id/test_recyclerView"
app:layout_anchorGravity="right|bottom" />
 
</android.support.design.widget.CoordinatorLayout>
    实现点击事件弹出 Snackbar
    
    
mFAB = (FloatingActionButton) findViewById(R.id.test_fab);
mFAB.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Snackbar.make(v,"This is snackbar",Snackbar.LENGTH_SHORT).show();
}
});
    效果如下
     GIF.gif
    Snackbar 并没有出现在 FloatingActionButton 之上,而是 FloatingActionButton 利用 CoordinatorLayout 的回调自动上移,并在 Snackbar 消失后,返回原来的位置。

CoordinatorLayout & App Bar

         现在我们已经用了 Toolbar 作为了 App Bar,但是为了让 Toolbar 能利用 CoordinatorLayout 的协调功能 ,用 AppBarLayout 包装 toolbar,这样能让 AppBarLayout 中的 view (如 toolbar, tablayout)能对一些 view(如 RecyclerView,NestedScrollView)的滚动事件做出响应,同时 ,像 RecyclerView 要添加 app:layout_behavior 属性。
    先添加布局
    
    
<?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:id="@+id/test_coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent">
 
<android.support.design.widget.AppBarLayout
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
 
<android.support.v7.widget.Toolbar
android:id="@+id/test_toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:background="@color/colorPrimary" />
</android.support.design.widget.AppBarLayout>
 
<android.support.v7.widget.RecyclerView
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:id="@+id/test_recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
 
<android.support.design.widget.FloatingActionButton
android:id="@+id/test_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16sp"
android:src="@mipmap/ic_done"
app:layout_anchor="@id/test_recyclerView"
app:layout_anchorGravity="right|bottom" />
 
</android.support.design.widget.CoordinatorLayout>
          app : layout_behavior = "@string/appbar_scrolling_view_behavior" , 这个是系统默认的一个ScrollingViewBehavior。
         PS: 默认的我们没有给 RecyclerView 添加 app:layout_behavior 属性,这个时候问题就来了,因为 CoordinatorLayout 是继承自 FrameLayout 的,所以这个 AppBar 会在 RecyclerView 的上方。只有添加 了 app:layout_behavior ,RecyclerView 出现在 AppBar 下方。哎,用一个控件还到处是坑~
    运行效果

捕获.PNG
    根据上面的描述 ,AppBar 中的 child view 能响应 RecyclerView 的滚动事件,既然这样的我们再在 AppBar 中加入一个 TabLayout   
   
   
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
 
<android.support.v7.widget.Toolbar
android:id="@+id/test_toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:background="@color/colorPrimary" />
 
<android.support.design.widget.TabLayout
android:id="@+id/test_tablayout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
    初始化 TabLayout
   
   
mTabLayout = (TabLayout) findViewById(R.id.test_tablayout);
mTabLayout.addTab(mTabLayout.newTab().setText("Tab1"));
mTabLayout.addTab(mTabLayout.newTab().setText("Tab2"));
mTabLayout.addTab(mTabLayout.newTab().setText("Tab3"));
    既然要让 AppBar 中的 child views 响应滚动事件,我们就得给需要响应的 child view 设置滚动标志 app:layout_scrollFlags
    现在只给 Toolbar 添加标志
   
   
<android.support.v7.widget.Toolbar
android:id="@+id/test_toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:background="@color/colorPrimary"
app:layout_scrollFlags="scroll" />
    理论上说只能 Toolbar 能响应 RecyclerView 的滚动事件,那我们看下实际效果
     GIF.gif
    从结果看,确实只有 Toolbar 发生了移动,TabLayout 并没有作出动作。不过请注意,Toolbar 是什么时候再出现的? 是不是往下滑动就会出现?其实并不是,只有当 RecyclerView 滑动到顶部的时候 ,再往下滑动 Toolbar 才会出现 ,这个在后面会对比看效果的,这个注意下。

     Flag 包括如下值:
         scroll:任何想滚动的 view 都要有这个 flag,如果不设置这个值 ,它就是一起出现在屏幕的顶部
         enterAlways:只要向下滚动 ,就会导致 view 的出现。
         enterAlwaysCollapsed:当child view 设置了最小高度,同时也设置了这个属性,那么这个 child view 在开始的时候只以最小的高度进入屏幕 ,当像 RecyclerView这个的控件滑动到顶部的时候,再往下滑动,child view 才会完全展开
         exitUntilCollapsed:child view 会滑出屏幕 ,直到达到最小的高度就不滑动了。

    这几个值字面上理解与实际从代码解释都有点头大,我会从我理解的角度带领大家去理解这些坑。
    首先,必须明确一点,如果想让 AppBar 中的 child view 滚动 ,就要设置 scroll,不想滚就不设置。
    我们再给 Toolbar 增加另外一个属性值 enterAlways
   
   
<android.support.v7.widget.Toolbar
android:id="@+id/test_toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:background="@color/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways" />
    看看效果
     GIF.gif
    不知道大家有没有发现只设置 scroll 和 设置 sroll | enterAlways 的区别 ,加上了 enterAlways 后,只要向下滑动就会出现 Toolbar,而只设置 scroll 的,需要 RecyclerView 达到顶部再往下滑动,Toolbar 才会出现。

    
    再看看 enterAlwaysCollapsed  ,先添加这个属性看看
   
   
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
 
<android.support.v7.widget.Toolbar
android:id="@+id/test_toolbar"
android:layout_width="match_parent"
android:layout_height="100dp"
android:minHeight="60dp"
android:background="#ffff0000"
app:layout_scrollFlags="scroll|enterAlwaysCollapsed" />
 
<android.support.design.widget.TabLayout
android:id="@+id/test_tablayout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
看看效果    

GIF.gif
实际效果看,怎么和描述的不一样啊,不是说好了先以最小的高度出现,然后当 RecyclerView 滑动到顶部再展开全部吗 ? 我遇到这个问题的时候 baidu了一把,没找到答案,google了一把,居然也没找到答案 ,找到的都是TM的类似翻译官方的例子,根本就没有对这个属性进行一次实际的考究,当时我就爆粗口了,只能自己找办法了。好了,从刚才效果看,是 RecyclerView 滑动到顶部后,Toolbar 才出现的,这与只设置了 scroll 的效果是一致 的, 那么是不是要再加上一个 enterAlways 才能有效果呢,我们看看
     GIF.gif
    效果是与描述的一致 ,在向下滑动的时候 ,只出现了最小的高度( 60dp ),RecyclerView 滑动到了顶部后,才展开全部,不过有人会问,这有个鸟用啊,我当时也是这么想的,别急,往后看~
    
    再看看 exitUntilCollapsed
    
    
<android.support.v7.widget.Toolbar
android:id="@+id/test_toolbar"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#ffff0000"
android:minHeight="60dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed" />
    这里并没有添加的 enterAlways ,其实也可以添加,具体看你要的效果了
    看看效果
       GIF.gif
    与预期的没什么不同,ok,这样我们就把这几个 flag 搞清楚了,现在的问题的是,后面那两个 flag 有个毛用?继续看~
    
    首先,我先给 Toolbar 再包装一层 CollapsingToolbarLayout 。停!!!什么? CoordinatorLayout 还没搞明白呢,怎么又来了一个! 我只能说,不要惊慌,看这个控件的名字,就是对 Toolbar 进行压缩折叠的,看看布局
   
   
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
 
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="256dp"
android:background="@mipmap/ss"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
 
<android.support.v7.widget.Toolbar
android:id="@+id/test_toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
app:layout_collapseMode="pin" />
</android.support.design.widget.CollapsingToolbarLayout>
 
<android.support.design.widget.TabLayout
android:id="@+id/test_tablayout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
 
</android.support.design.widget.AppBarLayout>
    PS:细心的人看到这里会发现  CollapsingToolbarLayout 并没有 minHeight 属性,是的,它会自动检测最小高度的
    我们先看看效果再解释下一些属性
     GIF.gif
    此时此刻看到这里,心情是不是稍微有点喜悦,这个简单的代码就实现了这个装B如风的效果。好了,如果心中有一丝喜悦,我们就看看 CollapsingToolbarLayout 的属性吧
    app:contentScrim : 当收缩到 Toolbar 的高度时候,设置的一个遮罩层,从效果看,成为了 Toolbar 的背景色
    app:expandedTitleMarginStart:展开后,Title 距离左边的距离
    app:expandedTitleMarginEnd:展开后,Title 距离右边的距离
    有人要问了,这两个属性有叼用?从效果看,是限制 Title 的显示范围,确实这样设计比较美观
    在 Toolbar 中有个 app:layout_collapseMode = "pin" ,这个是说固定 toolbar ,也就是说整个 CollapsingToolbarLayout的最小高度就是 Toolbar 高度了

    再明白这些属性之后,再换个 flag   
   
   
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="256dp"
android:background="@mipmap/ss"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed">
     GIF.gif
    这个就不用再说了吧~我写着都累了

     不知道大家注意没,我们给 CollapsingToolbarLayout 添加一个背景,向上滑动的时候 ,背景硬生生的移出了顶部,是不是很生硬,现在我们来改变下
   
   
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="256dp"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
 
 
<ImageView
android:background="@mipmap/ss"
android:id="@+id/backdrop"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:fitsSystemWindows="true"
app:layout_collapseParallaxMultiplier="0.9"
app:layout_collapseMode="parallax" />
 
<android.support.v7.widget.Toolbar
android:id="@+id/test_toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
app:layout_collapseMode="pin" />
</android.support.design.widget.CollapsingToolbarLayout>
    添加一个 ImageView 当作背景,然后设置一个视差效果, app:layout_collapseMode = "parallax" ,视差的比例是 0.9 ,看下效果
     GIF.gif
    这样看起来是不是感觉 RecyclerView 覆盖了那个背景,大家可以比较着看,我也是对比看了几次~
    
这篇文章只能说是对 CoordinatorLayout 的一个入门,后续我会继续完善对 CoordinatorLayout 的课题 。 如果大家喜欢,可以点个赞~

发布了44 篇原创文章 · 获赞 30 · 访问量 400万+

猜你喜欢

转载自blog.csdn.net/zwlove5280/article/details/51217994