简介
ViewPager2内部使用RecyclerView实现,并提供了增强功能
特性
- 禁止滑动
Adapter
由于是内部是RecyclerView,因此可以使用RecyclerView.Adapter<>
若子页为Fragment或Activity,则可使用FragmentStateAdapter
懒加载
当ViewPager2使用FragmentStateAdapter时,可通过setoffscreenPageLimit(int limit)设置离屏缓存数量,当limit<1时,不会进行预加载,默认为-1,VP则是默认为1
可实现加载布局,但不加载数据的懒加载,即在resume调用方法进行加载(handler执行)
当没有设置offscreenPageLimit离屏缓存时,VP2的RecyclerView会缓存前两个Item以及后面预抓取一个Item
设置offscreenPageLimit为1时,会在左右离屏新增一个缓存的Item,即缓存总共5个Item
一屏多页
设置VP2的left和right的padding,并设clipToPadding = false
嵌套滑动冲突
由于ViewPager2内部通过RecyclerView实现,其onInterceptTouchEvent方法返回isUserInputEnabled&&super.onInterceptTouchEvenet
嵌套滑动中的内部控件需要滑动时,设置父控件不拦截事件requestDisallowInterceptTouchEvent(true)
嵌套滑动中的内部控件不需要滑动时,设置父控件不拦截事件requestDisallowInterceptTouchEvent(false)
增量更新DiffUtil
使用DiffUtil进行增量更新,调高性能,使用notifyDatasetChanged进行全量更新
PageDiffUtil内部有方法areItemsTheSame和areContentsTheSame比较两个item和其内容是否相同,前者表示View是否可以复用,后者表示是否需要更新内容 前者返回true时才能调用后者,后者返回fasle才能调用getChangePayLoad,用于更新对应Item
//使用DiffUtil更新数据
val callback = PageDiffUtil(mItems, newItems)
val difResult = DiffUtil.calculateDiff(callback)
mItems.clear()
mItems.addAll(newItems)
difResult.dispatchUpdatesTo(adapter)
转场动画Transformer
val multiTransformer = CompositePageTransformer()
multiTransformer.addTransformer(ScaleInTransformer())
multiTransformer.addTransformer(MarginPageTransformer(10))
ViewPager2.setPageTransformer(multiTransformer)
RecyclerView缓存机制
RecyclerView通过内部类Recycler管理缓存,RecyclerView本身时一个ViewGroup,滑动时需要增删子View,Recycler缓存的是ViewHolder,便于复用子View和绑定的数据
四级缓存
缓存滑动时即将与RecyclerView分离的ViewHolder,按position或id缓存,默认缓存数量为2
不重新创建视图和绑定数据
ViewHolder缓存池,本质为SparseArray,key为ViewType(int),value存放的是ArrayList< ViewHolder>,ArrayList默认存放5个ViewHolder
不重新创建视图,但重新绑定数据
mAttachedScrap、mCachedViews官方视为同一级
RecyclerView滑动时触发onTouchEvent#onMove,此时会进行回收和复用ViewHolder,这部分工作由LayoutManager负责
当RecyclerView重新布局时会依次执行下面几个方法
onLayoutChildren():对RecyclerView进行布局的入口方法
fill():负责对剩余空间进行不断填充,调用layoutChunk()
layoutChunk():填充View,最终通过Recycler中找到合适的View
onLayoutChildren() —> fill() —> layoutChunk() —> next() —> getViewForPosition()
getViewForPosition() 是从RecyclerView的回收机制实现类Recycler中获取合适的View
getViewForPosition() 就是依次通过四级缓存查找对应的ViewHolder,若都找不到则重新创建
ViewCacheExtension
第三级缓存,开发者自定义缓存
mAttachedScrap用来处理可见屏幕的缓存,而mCachedViews里存储的数据根据position来缓存,里面的数据随时可能会被替换
mRecyclerPool则按ViewType为key存储,不能按position存储,且还得重新绑定数据,而业务汇总优势需要在特定位置一直展示某个view,其内容不变,为避免重新创建View和重新绑定数据
与ListView缓存机制对比
mAttachedScrap和mCachedViews、mRecyclerViewPool能够快速重用itemView
而RecyclerView的优势在于对mCachedViews的使用,无需重新创建和绑定数据
mRecyclerPool可供多个RecyclerView共同使用,对缓存机制进行补强和完善,对于频繁更新和局部刷新等,RecyclerView更强大和完善
offscreenPageLimit离屏缓存
setOffscreenPageLimit设置的是VP2的离屏显示个数,默认是-1,
因为RecyclerView中的布局是通过LayoutManager,所以真正进行离屏计算是在VP2.LinearLayoutManagerImpl#calculateExtraLayoutSpace()中
该方法计算的是LinearLayoutManager布局的额外空间,LinearLayoutManagerImpl继承自LinearLayoutManager。
getPageSize()表示ViewPager2的宽度,左右离屏大小都为getPageSize() * pageLimit。extraLayoutSpace[0]表示左边,extraLayoutSpace[1]表示右边。
比如设置offscreenPageLimit为1,可以认为是把屏幕扩大到3倍。
左右两边各有一个离屏PageSize的宽度(左右不可见)
FragmentStateAdapter缓存
FragmentStateAdapter继承自RecyclerView.Adapter,所以可以直接通过setAdapter设置给VP2。我们知道FragmentStateAdapter作为Adapter时,每个Item都是Fragment
每个Fragment内部根布局为FrameLayout,并设置唯一ID
FragmentStateAdapter内部有两个数组,分别存储position分别对Fragment和ID的映射表
当VP2滑动时,当前页前两个item会被缓存到mCachedViews中,超过2个时,将其转移到RecyclePool中
原文地址:https://blog.csdn.net/weixin_51109304/article/details/131493905
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_47412.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!