当 PagerSnapHelper 出现后,使用 RecyclerView 代替 ViewPager 越来越可行了。 RecyclerView 的动态更新是基础功能,而 ViewPager 的动态更新一直是这个控件的痛点。
使用 RecyclerView + SnapHelper 展示简单的 View 翻页是没有问题,不过想进一步实现 RecyclerView 动态显示 Fragment 就遇到各种组件的缺失。
一. ViewHolder 显示 Fragment
要在 RecyclerView.ViewHolder 内显示 Fragment。首先需要一个类似 android.support.v4.app.FragmentPagerAdapter
管理 Fragment 的动态绑定的 RecyclerView.Adapter。
使用 FragmentManager 和 FragmentTransaction 添加 Fragment 时,需要页面(FragmentContainer) 中一个 ViewGroup 的 Id 进行绑定。RecyclerView.ViewHolder 的几个生命周期对于我们怎样绑定 Fragment 很重要:
具体代码参见 FragmentRecyclerAdapter.java
-
onCreateViewHolder
基于 FrameLayout 创建空的 ViewHolder
-
onBindViewHolder
基于
ViewCompat.generateViewId()
和当前 position 对 ViewHolder 中 itemView (FrameLayout)重新 setId, 保证 Id 唯一。 -
onViewAttachedToWindow
当 ViewHolder 开始在页面显示时,对 Fragment 进行 add 或 attach 以及 setUserVisibleHint 等处理。 注意,在 onBindViewHolder 时,不能马上操作 FragmentTransaction,因为 ViewHolder 的 itemView 还没有被添加到 ViewTree 中,FragmentContainer 是找不到设置的 Id 的
-
onViewDetachedFromWindow
ViewHolder 离屏不显示,只对 Fragment 进行 setUserVisibleHint 等操作,保证 Fragment 生命周期正确。
-
onViewRecycled
ViewHolder 开始被回收复用时,对绑定在 itemView 上的 Fragment 进行 detach 。
二. RecyclerView 滚动监听 SnapHelper 选中页面
我们还缺少 ViewPager.OnPageChangeListener
这样方便的回调。
- onPageScrollStateChanged(int state)
- onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
- onPageSelected(int position)
具体代码参见 SnapPageScrollListener.java
继承 RecyclerView.OnScrollListener
,其中 onScrollStateChanged(RecyclerView recyclerView, int newState)
已经实现了第 1 个回调。 剩下两个回调需要在 onScrolled(RecyclerView recyclerView, int dx, int dy)
计算实现。
SnapHelper 的 findSnapView
和 calculateDistanceToFinalSnap
能帮助我们确定选中 View 的位置和距离。 避免使用如 LinearLayoutManager.findFirstVisibleItemPosition 等实现类方法来计算。
只是在滚动中,例如 A、B页面滚动到 50% 之后时, findSnapView
命中的目标会 A 切换到 B。与 ViewPager 中 A 页面一定是滑动到 100% 才从 A 切换到 B 有些出入。
三. TabLayout 控件支持
现有的 TabLayout 开源控件一般基于 ViewPager 的数据源和滚动接口来实现。
例如 SmartTabLayout , Fork一份,将原控件中 ViewPager 的接口和数据源剥离,传入 RecyclerView 和 SnapHelper,配合上面的 SnapPageScrollListener 就能很快改装成支持 RecyclerView 的 TabLayout。 同时还能支持 RecyclerView 的动态更新。
具体代码参见 SmartTabLayout2.java
最后整个配套使用如下:
项目地址: RecyclerPager
另外,有两个招聘广告,感谢查看了解:
【Android开发工程师】www.lagou.com/jobs/180879…
【前端开发工程师】www.lagou.com/jobs/415543…
简历备注【掘金】 ?