CoordinatorLayout的使用

最近项目有一个需求,做出类似闲鱼鱼塘界面的效果。如下图:CoordinatorLayout的使用

所以想到用CoordinatorLayout+AppBarLayout+CollapsingToolbarLayout去搭建此界面。

CoordinatorLayout
实际上是一个更强大的FrameLayout, 可以通过Behavior 来控制其中各个child view的交互行为. 也可以指定anchor来指定floating view相对于其他某个View的位置. 比如Floating Action Button在显示Snackbar的时候自动向上移动.

为了使Toolbar响应滚动事件, 需要给它外边包一个AppBarLayout.
它是一个纵向的LinearLayout, 必须要作为CoordinateLayout的直接child使用.
然后, 我们需要定义AppBarLayout和我们scroll的内容View的关系.
这里可以是一个RecyclerView, 或者其他支持嵌套scrolling的view, 比如NestedScrollView

(实际上View类就有方法setNestedScrollingEnabled(), 但是还是需要View自己实现nested scrolling的功能, 否则这个开关也没有效果.)

support library提供了@string/appbar_scrolling_view_behavior, 它映射到AppBarLayout.ScrollingViewBehavior.
它是用来告诉AppBarLayout下面那个scroll view上的scroll事件什么时候发生.
所以这个属性必须在触发事件的view上指定, 比如:

<android.support.v4.widget.NestedScrollView
android:id="@+id/nsv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:scrollbars="none"
app:layout_behavior="@string/appbar_scrolling_view_behavior">

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

当CoordinatorLayout看到自己的child(比如NestedScrollView)声明了这个属性, 就会在自己的其他child中寻找相关的view(AppBarLayout).
这样, 当NestedScrollView发生scroll事件的时候, AppBarLayout和其中的views都会被通知到.

滚动事件怎么通知到AppBarLayout的呢? 还需要一个属性: app:layout_scrollFlags

  • scroll:该view显示时,只有在滚动视图顶部向上滚动时,该view才会慢慢消失。 该view消失后,只有在滚动视图顶部向下滚动时,该view才会慢慢出现。
  • enterAlways:表示只要列表上方内容滚动出现, View就应该出现. 适用的情形: 当把列表滚到底部时, Toolbar被隐藏了, 一旦回滚一点儿, Toolbar就应该立即出现. 如果不设置这个flag, 默认的行为是一直要把列表滚到顶部, Toolbar才会出现.
  • enterAlwaysCollapsed:正常情况下, 如果只有enterAlways被指定, 在列表向下滚动的过程中Toolbar将会一直展开.如果同时指定了enterAlwaysCollapsedminHeight, 那么开始滚动以后, 只滚动到minHeight为止, 直到滚动到达列表顶部的时候, view才会展开到全部高度.
  • exitUntilCollapsed: 正常只指定scroll的情况下, 向下滑动将会使得整个Toolbar移动到不见.如果同时指定了exitUntilCollapsedminHeight, 那么将会收缩到minHeight为止, Toolbar不会一直滚动和退出屏幕.
  • snap:使用了这个属性, 等scroll事件结束的时候, View可见的尺寸小于它的50%, 则它会直接消失, 如果大于50%, 则它会完整地出现.

若要实现Toolbar折叠的效果,需在Toolbar外面包一层CollapsingToolbarLayout,这个类必须作为AppBarLayout的直接child使用。

<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
app:collapsedTitleGravity="center"
app:collapsedTitleTextAppearance="@style/yuquan_collapsed_text"
app:contentScrim="@color/white"
app:expandedTitleGravity="top"
app:expandedTitleMarginStart="60dp"
app:expandedTitleMarginTop="35dp"
app:expandedTitleTextAppearance="@style/yuquan_expanded_text"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
  <ImageView
  android:id="@+id/logo"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:contentDescription="@null"
  android:fitsSystemWindows="true"
  android:scaleType="fitCenter"
  android:src="@drawable/android_logo"
  app:layout_collapseMode="parallax"
  app:layout_collapseParallaxMultiplier="0.1" />
    <android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_size"
app:contentInsetEnd="0dp"
app:contentInsetStart="0dp"
app:layout_collapseMode="pin">

<ImageView
android:id="@+id/iv_yuquan_back"
android:layout_width="@dimen/toolbar_size"
android:layout_height="@dimen/toolbar_size"
android:layout_gravity="left"
android:clickable="true"
android:padding="12dp"
android:src="@drawable/icon_yuquan_back_gray" />

<ImageView
android:id="@+id/iv_yuquan_more"
android:layout_width="@dimen/toolbar_size"
android:layout_height="@dimen/toolbar_size"
android:layout_gravity="right"
android:clickable="true"
android:padding="12dp"
android:visibility="gone"
android:src="@drawable/icon_yuquan_more_gray" />
</android.support.v7.widget.Toolbar>
</android.support.design.widget.CollapsingToolbarLayout>

包了这个类之后, setTitle要调用这个类的方法:

CollapsingToolbarLayout collapsingToolbar = (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
collapsingToolbar.setTitle("Title");

 这里可以设置ImageView折叠展开的效果:

  layout_collapseMode属性设置为parallax,在内容滚动时,CollapsingToolbarLayout中的View(比如ImageView)也可以同时滚动,实现视差滚动效果,通常和app:layout_collapseParallaxMultiplier属性(设置视差因子)搭配使用,其值为0~1;设置上为pin,则不会有滚动效果。

说一说遇到的坑吧:

因为项目框架搭建的列表全部使用ListView,所以最初viewpager里面放的也是ListView。因为Listview在Coordinatorlayout中无法响应滚动事件,所以自己实现NestedScrollingChild的功能,待全部写完,测试时发现在5.0以下系统竟然只能滑动一屏!

Google一圈才发现,这只对5.0+系统有效,最好的解决办法是用RecyclerView,因为内部实现了NestedScrollingChild,处理了“与父view交互”的嵌套滑动。

所以在使用Coordinatorlayout时,最好最好最好配合RecyclerView使用。

By LiYing.