Reset nested scroll effect manually

使用 CoordinatorLayout + AppBarLayout 可以轻松实现这样的嵌套滑动效果:

当列表往上滚动的时候,Toolbar 可以随之往上滚直到消失,然后往下滚回来的时候,其也会跟着滚下来。

实现方式很简单,这里只是做一个简单的演示:

<android.support.design.widget.CoordinatorLayout>
	<android.support.design.widget.AppBarLayout>
		<FrameLayout app:layout_scrollFlags="scroll|enterAlways">
		</FrameLayout>
	</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayou>

layout_scrollFlags 这个决定了这个 View 在嵌套滑动里的行为,如果不知道各个值代表的意思,请通过搜索其他文章理解,这并不是本文的重点。

那么,有这么一个需求:在列表滑动上去后,想要不通过手动滚下来的方式让 AppBarLayout 的内容随之滚下来。

这个需求可能看着很奇怪,但是应该还是挺常见的:假设有一个 View,承载了显示一个带 ToolBar 和 RecyclerView,并带有上文所说的嵌套滑动效果,而且是在某些操作才会显示出来;那么,某些用户操作,比如按下返回按键,可以让这个 View 消失,与之同时,让通过设置 ScrollFlag 达到的滚动效果随之消失,让下次显示这个 View 的时候就像没有滚动过一样。

乍一看可能可以这么做:

  • 手动调用 RecyclerView 的 ScrollTo 方法,让列表滚到最上方,自然 ToolBar 就能滚下来了
  • 手动设置 AppBarLayout 内容的 Top/Bottom

第一个方法是不可行的,因为这个嵌套滑动必须是跟手指也就是接收 Touch 事件才能触发;而第二个方法,其实通过看源码什么的,你可以知道最终改变 AppBarLayout 的内容的是 mTop 和 mBottom 这两个 fields,改变这两个值(通过offsetTopAndBottom())为原来的值,理论上说是可以的。但是其实并不行:在调用这个方法之后,当请求重新布局后,AppBarLayout 的内容又回到滚动了的状态。

那么,是否可以从源头解决呢?也就是通过设置 scrollFlag 来取消原本的嵌套滑动效果?答案是可以的:

AppBarLayout.LayoutParams layoutParams = (AppBarLayout.LayoutParams) mSearchBox.getLayoutParams();
        layoutParams.setScrollFlags(0);
        mSearchBox.setLayoutParams(layoutParams);

大概就是这样,mSearchBox 是应用了 layout_scrollFlags 的 View。如果有一个滚动下来的效果?那么可以使用 ValueAnimator ,在 onAnimationUpdate() 调用 offsetTopAndBottom() 方法,就可以了。