好奇移动端、桌面端是怎么实现列表控件渲染大量元素不卡顿的?

56 天前
 rcocco
网页端是有多少 DOM 元素就渲染多少元素,不管这些元素是不是用户当前视口可见的,所以元素一多就会很卡。每次都要专门把渲染的逻辑写成虚拟滚动来解决这个问题,但用过的一些虚拟滚动库总是有各种各样的限制或小毛病,例如要求元素等高,滚动到底部不对劲等等。

我就很好奇其他端,像移动端和桌面端都是怎么解决这个问题的?搜索 [安卓 虚拟滚动] 还搜不到什么东西
3556 次点击
所在节点    程序员
40 条回复
sduoduo233
56 天前
安卓是 recyclerview
abcbuzhiming
56 天前
移动端我不清楚。但是桌面端的话,我没听说过传统 UI 的列表控件有用虚拟滚动的,实际上,当元素量够大的时候,一样会卡的,只是桌面端大部分时候处于性能溢出的状态,且内存管够,所以一般遇不到那个能让你卡的数量级。
Irisxx
56 天前
主要是归功于对象池的重用机制,辅之以 LRU 这些缓存机制优化。
verrickt
56 天前
微软的 GUI 框架把相关的技术叫做 UI Virtualization ,有兴趣可以看看
lmw2616
56 天前
android 用 recyclerview ,也是类似于虚拟滚动
chiaf
56 天前
你搜索 iOS UITableView 应该能搜到😄
很早之前的经典面试题,说一下 UITableView Cell 的复用原理
kemchenj
56 天前
其它端不清楚,iOS 端其实就是虚拟滚动,列表会维护一个重用池,把不可见的 cell 塞进去,然后需要展示的时候从里面拿 cell 出来显示,如果发现不够就再补充新的进来

iOS 封装得还行,但也免不了各种限制和小毛病,都是需要开发者额外做一些处理去完善体验,例如预先计算每个元素的高度以便把列表撑开之类的...

感兴趣的话可以搜一下“UITableView 重用”
A4l1CteRQHlG1Bs8
56 天前
回收,重用,缓存
UnluckyNinja
56 天前
如果从只渲染可见部分的组件来看,那基本上都可以算作虚拟滚动(否则就是加硬件了)
你用的库总是有各种各样的不完美,可能是因为复杂度难以实现/怕导致库臃肿(所以固定高度),或者虚拟高度计算不正确。
根本原因在于虚拟高度需要根据内部组件的实际大小调整以正确计算滚动位置。
你看像 twitter 也是虚拟滚动,但你要是快速拉到中间再缓慢向上拉,会发现 twitter 的滚动条也在闪,(猜测)这就是在修正假定的未渲染元素的高度到渲染完后实际高度,并相应调整总高度。
如果你是想写前端的一个虚拟滚动组件,可以参考 VueUse 推荐的这个独立虚拟滚动组件 https://vue-virtual-scroller-demo.netlify.app/dynamic
superkeke
55 天前
iOS UITableView ,android recyclerview ,移动端这是最基本的了。
tangmanger
55 天前
wpf 大列表有虚拟化 只渲染展示的
shunia
55 天前
解决方案全都是虚拟列表,没有例外。方案细节基本就是元素复用、列表两端留缓冲区、高度重新计算等。

你觉得不好用是因为这个没有完美的解决方案,比如你说的等高问题,应该是想要考虑保留列表滚动位置,否则根本不必等高。

这些都是一说出来就明白的基础原理,并不是哪个技术方案本身能解决的,桌面端列表大了不虚拟也会卡的爆炸,只是在同一个硬件设施上比网页端能多承受一些而已。
hefengwqz
55 天前
@abcbuzhiming 桌面端我们之前开发性能调优工具的时候,数据表格就是做的虚拟滚动,Android 手机录制几十秒解析出来的数据就有百万条。
duanxianze
55 天前
都是虚拟滚动,上千上万的元素啥玩意也顶不住的,只不过浏览器的限制导致 dom 复用总有问题,安卓 ios 和 win 内置的相关逻辑
chniccs
55 天前
安卓最开始的时候是 listview ,后面换成了 recyclerview ,不过都是复用,但是当年试过,不复用的话,列表内容不复杂,不是太快的滑动也没有很卡,只是内存会爆
wya93
55 天前
虚拟分页,
iOCZS
55 天前
反正你只能看到一个屏幕的东西,我提前准备好三屏,够你看的了
zpxshl
55 天前
你搜不到是因为,安卓列表基本都用 rv 实现,不存在问题,自然没有“解决方案”
unco020511
55 天前
移动端的列表控件会在背后做非常多的工作,以便解决列表渲染的性能.就拿 android 端的 recyclerview 举例:
1. 视图复用( View Recycling ):RecyclerView 通过 ViewHolder 模式来复用已经创建的视图。简单来说,当某个视图滚出屏幕时,它不会被销毁,而是会被放入一个"回收池"中。当新的视图需要显示时,RecyclerView 会从这个回收池中取出一个视图,并绑定新的数据。这大大减少了视图创建和销毁的开销。

2 .按需加载( Lazy Loading ):RecyclerView 只会创建和绑定当前屏幕上可见的视图,以及少量即将进入屏幕的视图。这样可以有效减少内存消耗和处理时间。

3. 布局管理器( LayoutManager ):RecyclerView 使用 LayoutManager 来决定如何在屏幕上排列子视图。不同的 LayoutManager 可以实现不同的布局方式,如线性布局、网格布局等。LayoutManager 负责计算哪些视图需要显示,哪些可以复用。

4 .差分更新( Diff Util ):RecyclerView 支持高效的数据更新。当数据集发生变化时,可以使用 DiffUtil 来计算新旧数据集之间的差异,只更新那些真正改变的部分,而不是重新渲染整个列表。
debuggerx
55 天前
条目非等高的长列表还要带滚动条,原理上就没办法高效、完美解决,只能是各种取舍,有时是技术上,有时是设计上。
或者换句话说,只要原理上无法避免大量元素 layout 的场景,怎么都会卡,只是在同等硬件配置下不同的语言和框架会出现卡顿现象的量级会有所不同。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1059281

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX