RecycleView 嵌套卡顿

RecycleView 嵌套卡顿

https://blog.csdn.net/qq_30983519/article/details/81280274

  1. 共用 RecycledViewPool,holder. innerRecyclerView. setRecycledViewPool (viewPool)
    2. setInitialPrefetchItemCount (int) 来优化嵌套时预加载性能
  2. 设置 recycleview 的子项缓存 rv. setItemViewCacheSize (200);
  3. rv. setHasFixedSize (true);
  4. recyclerview 嵌套 recyclerview 的时候, adapter 全局变量

NestedScrollView 嵌套 recyclerView

NestedScrollview 和 recycler View 嵌套的时候, recyclerview 的缓存机制失效了, 这种情况有没有什么好的解决办法呢?
NestedScrollView 传递给子 View 的测量模式为 UNSPECIFIED,RecyclerView 在 UNSPECIFIED 的测量模式下,会不限制自身的高度,即 RecyclerView 的窗口高度将会变成所有 item 高度累加后加上 paddding 的高度。因此,表现出来就是 item 一次性全部加载完成。
这样做在 RecyclerView 的 item 数量较少的时候可能没什么问题,但是如果 item 数量比较多,随之带来的性能问题就会很严重。

推荐使用 RecyclerView 的多样式布局实现,毕竟 RecyclerView 自带滑动,没必要外层套一个 ScrollerView 或者 NestedScrollView

必须嵌套,解决方案:
懒饭详情页嵌套效果仿写(View/Compose 实现) - 简书
问题本质上其实就是因为高度不确定导致复用失效了,那其实指定 RecyclerView 的高度即可,例如屏幕的高。

[[NestedScrollingParent]]

1
2
3
4
5
6
7
8
9
10
11
/**
* 开始滑动时,子视图会优先回调该方法。父容器可以处理自己的滚动操作,之后将剩余的滚动偏移量
* 传回给子视图。(可由 NestedScrollingChild2的 dispatchNestedPreScroll 方法触发)
*/
void onNestedPreScroll (@NonNull View target, int dx, int dy, @NonNull int[] consumed, @NestedScrollType int type);

/**
* 子视图处理完剩余的滚动偏移量后,若还有剩余,则将剩余的滚动偏移量再通过该回调传给
* 父容器处理。(可由 NestedScrollingChild2的 dispatchNestedScroll 方法触发)
*/
void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @NestedScrollType int type);

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
override fun onNestedPreScroll(target: View, dx: Int, dy: Int, consumed: IntArray, type: Int) {
if (scrollY < scrollViewHeadHeight) {
if (scrollY + dy < scrollViewHeadHeight) {
scrollBy(0, dy)
consumed[1] = dy
} else if (scrollY + dy > scrollViewHeadHeight) {
val scrollViewNeedScrollY = scrollViewHeadHeight - scrollY
scrollBy(0, scrollViewNeedScrollY)
consumed[1] = scrollViewNeedScrollY
}
}
}

override fun fling(velocityY: Int) {
val dy = FlingUtil.getDistanceByVelocity(context, velocityY)
if (scrollY < scrollViewHeadHeight) {
if (scrollY + dy <= scrollViewHeadHeight) {
super.fling(velocityY)
} else if (scrollY + dy > scrollViewHeadHeight) {
val scrollViewNeedScrollY = scrollViewHeadHeight - scrollY
//让NestedScrollView先处理所有的滚动事件
val scrollViewNeedVelocity = FlingUtil.getVelocityByDistance(context, scrollViewNeedScrollY.toDouble())
if (velocityY > 0) {
super.fling(scrollViewNeedVelocity)
} else {
super.fling(-scrollViewNeedVelocity)
}
//把剩余的滚动事件交给RecyclerView处理
val recyclerViewScrollY = dy - scrollViewNeedScrollY
val recyclerViewNeedVelocity = FlingUtil.getVelocityByDistance(context, recyclerViewScrollY)
if (velocityY > 0) {
getChildRecyclerView(this)?.fling(0, recyclerViewNeedVelocity)
} else {
getChildRecyclerView(this)?.fling(0, -recyclerViewNeedVelocity)
}
}
}
}

上面的代码是针对嵌套滚动的情况进行处理的。根据代码的逻辑,可以理解如下:

  1. onNestedPreScroll() 方法用于处理嵌套滚动前的预处理。当嵌套滚动发生时,会调用该方法。参数说明如下:

    • target: 嵌套滚动的目标视图。
    • dx: 水平方向上的滚动距离。
    • dy: 垂直方向上的滚动距离。
    • consumed: 用于传递消耗的滚动距离的数组。
    • type: 滚动事件类型。

    在代码中,首先判断当前滚动的位置 scrollY 是否小于 scrollViewHeadHeight(一个预设的阈值)。如果小于该阈值,表示需要对滚动进行处理。

    • 如果 scrollY + dy 小于 scrollViewHeadHeight,直接进行滚动并消耗全部的垂直滚动距离 dy,将其存入 consumed 数组中。
    • 如果 scrollY + dy 大于 scrollViewHeadHeight,则需要将滚动限制在 scrollViewHeadHeight 的位置,即将滚动距离限制为 scrollViewHeadHeight - scrollY,并将此消耗的滚动距离存入 consumed 数组中。
  2. fling() 方法用于处理滑动手势的快速滚动。当手指快速滑动屏幕时,会调用该方法。参数说明如下:

    • velocityY: 垂直方向上的滑动速度。

    在代码中,首先判断当前滚动的位置 scrollY 是否小于 scrollViewHeadHeight

    • 如果小于该阈值,表示需要对滚动进行处理。
    • 如果 scrollY + dy 小于等于 scrollViewHeadHeight,直接调用父类的 super.fling(velocityY) 方法进行滚动。
    • 如果 scrollY + dy 大于 scrollViewHeadHeight,则需要将滚动限制在 scrollViewHeadHeight 的位置,即将滚动距离限制为 scrollViewHeadHeight - scrollY,并将此消耗的滚动距离存入 scrollViewNeedScrollY
    • 接下来,根据滚动速度 velocityY 计算出 scrollViewNeedScrollY 所对应的速度 scrollViewNeedVelocity
    • 如果 velocityY 大于 0,表示向上滑动,调用父类的 super.fling(scrollViewNeedVelocity) 方法进行滚动。
    • 如果 velocityY 小于等于 0,表示向下滑动,调用父类的 super.fling(-scrollViewNeedVelocity) 方法进行滚动。
    • 然后,剩余的滚动距离为 dy - scrollViewNeedScrollY,根据剩余距离计算出对应的速度 recyclerViewNeedVelocity
    • 最后,通过 getChildRecyclerView(this)?.fling(0, recyclerViewNeedVelocity) 将剩余的滚动事件交给嵌套的 RecyclerView 处理。

这段代码的目的是在特定的条件下对滚动和快速滑动进行限制和分发,以实现特定的滚动效果和交互行为。具体的实现细节和逻辑可能还需要结合其他代码来全面理解其功能和效果。


RecycleView 嵌套卡顿
http://peiniwan.github.io/2024/04/9183668c2c71.html
作者
六月的雨
发布于
2024年4月6日
许可协议