避免嵌套使用 ScrollView 组件
了解如何避免嵌套使用 ScrollView 导致的懒加载无法工作的问题。

在开发 Filmo 的过程中,在使用 LazyVStack 或 LazyVGrid 加载远程图片时,我遇到一个性能相关的问题:所有图片在视图出现的瞬间就全部开始加载,而不是预期中的随着滚动逐步加载。这个问题会导致:
- 应用内存占用突然飙升
- 用户界面出现明显卡顿
- 网络请求瞬间激增
原因分析
经过排查,这个问题通常是由嵌套使用 ScrollView 组件导致的。当出现嵌套 ScrollView 时:
- 外层 ScrollView 会尝试计算其内容的总高度
- 这个计算过程会导致它初始化内部的所有子视图
- 内层视图中的 LazyVGrid/LazyVStack 被强制提前初始化
- 即使使用了 Lazy 组件,其懒加载效果也被外层 ScrollView 的预加载行为覆盖
- 最终结果是所有图片同时请求加载,而非随着滚动逐步加载
ScrollView 在 TabView 应用中的最佳实践
对于具有多个 Tab 的应用,推荐将 ScrollView 放在每个 Tab 的主页面中,而不是更深层的子组件中。
- 清晰的视图层次结构:每个 Tab 只有一个主要滚动区域,避免嵌套
- 更好的性能:减少内存使用,因为只有当前选中的 Tab 会初始化其 ScrollView
- 统一的滚动体验:整个 Tab 内容有一致的滚动行为
- 简化下拉刷新实现:在 Tab 级别实现
.refreshable
更直观
推荐的代码结构:
TabView {
// 第一个标签页
NavigationStack {
ScrollView {
VStack {
HeaderView()
ContentListView() // 不包含自己的 ScrollView
FooterView()
}
}
.refreshable { /* 刷新逻辑 */ }
}
.tabItem { /* 标签配置 */ }
// 第二个标签页
NavigationStack {
ScrollView {
OtherTabContent() // 不包含自己的 ScrollView
}
}
.tabItem { /* 标签配置 */ }
}