简介

ViewPager2内部使用RecyclerView实现,并提供了增强功能

特性

android:orientation = “vertical”

android:layoutDirection = “rtl”

setUserInputEnabled()

对可修改的Fragment集合进行分页浏览底层集合更改调用notifyDatasetChanged来更新页面

支持局部更新,避免全局更新notifyDatasetChanged全量更新

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的leftrightpadding,并设clipToPadding = false

嵌套滑动冲突

由于ViewPager2内部通过RecyclerView实现,其onInterceptTouchEvent方法返回isUserInputEnabled&amp;&amp;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和绑定数据

四级缓存

缓存屏幕中可见范围的ViewHolder
不重新创建视图绑定数据

缓存滑动时即将与RecyclerView分离的ViewHolder,按positionid缓存,默认缓存数量为2
不重新创建视图绑定数据

开发者自行实现的缓存
不重新创建视图和绑定数据

ViewHolder缓存池,本质为SparseArray,key为ViewTypeint),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则按ViewTypekey存储,不能按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中

当前页为最后一页时,会缓存前三个页面

而当第一次加载时,没有onTouch操作,不会进行预抓取

原文地址:https://blog.csdn.net/weixin_51109304/article/details/131493905

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_47412.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注