NestedRecyclerView
仿淘宝、京东首页,通过两层嵌套的 RecyclerView 实现 tab 的吸顶效果
现已提供 Java 和 Kotlin 两种版本,具体可查看项目代码。
项目效果展示:
背景
我们自己的商城的首页和淘宝、京东首页效果类似,上面为配置数据,中间是各种分类频道,下面是商品流数据,商品流部分支持左右横滑,分类频道是支持吸顶的。
最早是用 CoordinatorLayout 实现,在 AppBarLayout 下放一个 RecyclerView,下面部分则放一个 ViewPager,ViewPager 里则是商品流的 RecyclerView,CoordinatorLayout 支持设置他的某个子 View 吸顶,这样基本能满足需求。
在CoordinatorLayoutFix 中修复了一些体验问题,基本可以让这种实现满足商业性的项目需求。
调研
在调用了淘宝和京东的实现发现可以通过两层 RecyclerView 来实现。
可以看到京东首页的实现是上面这样的。
大致实现方式
- 外部 RecyclerView 为 ParentRecyclerView,将需要吸顶的悬浮效果的 TabLayout 和 ViewPager 作为 ParentRecyclerView 的一个 item。
- 内部 RecyclerView 为 ChildRecyclerView,ParentRecyclerView 和 ChildRecyclerView 相互协调:
- 当 ParentRecyclerView 滚动到底部的时候,让 ChildRecyclerView 去滚动。
- 当 ChildRecyclerView 滚动到顶部的时候,让 ParentRecyclerView 去滚动。
利用 canScrollVertically 这个方法来判断当前 View 是否滚动到底或者是否滚动到顶。
//ParentRecyclerView
private boolean isScrollEnd() {
//RecyclerView.canScrollVertically(1)的值表示是否能向上滚动,false 表示已经滚动到底部
return !canScrollVertically(1);
}
//ChildRecyclerView
boolean isScrollTop() {
//RecyclerView.canScrollVertically(-1)的值表示是否能向下滚动,false 表示已经滚动到顶部
return !canScrollVertically(-1);
}
ParentRecyclerView 和 ChildRecyclerView 需要拿到对方的引用,以便能够协调滚动。
目前 ChildRecyclerView 是直接通过往上查找的方式来进行的。而 ParentRecyclerView 需要通过 ViewPager 来找到当前显示的是哪一个 ChidRecyclerView。
//ChildRecyclerView
private ParentRecyclerView findParentRecyclerView() {
ViewParent parentView = getParent();
while (!(parentView instanceof ParentRecyclerView)) {
parentView = parentView.getParent();
}
return (ParentRecyclerView)parentView;
}
//ParentRecyclerView
private ChildRecyclerView findNestedScrollingChildRecyclerView() {
if(getAdapter()!= null && (getAdapter() instanceof MultiTypeAdapter)) {
return ((MultiTypeAdapter)getAdapter()).getCurrentChildRecyclerView();
}
return null;
}
处理 fling 效果
在 RecyclerView 的 onScrolled 记录总的偏移,当 ParentRecyclerView 滑动到底部的时候,将多余的需要消费的总偏移转换成加速度,从而交给子 View 去 Fling,反之,类型。
处理嵌套滚动
如果不处理嵌套滚动,在某些边界场景下,当我们滑动不松手时会出现无法滑动的问题。
另外
新增 Tab 折叠动画
关于
博客:https://jasongaoh.github.io/
邮箱:jasongaohui@gmail.com
License
Copyright 2018 JasonGaoH
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions