提问人:chrysb 提问时间:7/21/2021 最后编辑:chrysb 更新时间:8/11/2022 访问量:4050
在 ScrollView 内的 LazyVStack 中具有可变高度的内容会导致卡顿/跳跃
Content with variable height in a LazyVStack inside a ScrollView causes stuttering / jumping
问:
XCode 版本 13.0 beta (13A5155e) & 针对 iOS 14 或 15
我的目标是在 SwiftUI 中创建一个聊天视图。这需要创建一个具有不同高度内容的 ScrollView。
经过大量调试,我确定如果 ScrollView 中的视图没有固定高度,则当您滚动到视图顶部时,它会卡顿。
––––
项目:下载此项目并亲自尝试
struct Message: Identifiable {
let id = UUID()
var text: String
}
struct ContentView: View {
@State var items: [Message] = MockData.randomMessages(count: 100)
var body: some View {
VStack {
Button("Shuffle items") {
items = MockData.randomMessages(count: 100)
}
ScrollView {
LazyVStack(spacing: 10) {
ForEach(items) { item in
Text(item.text)
.background(colors.randomElement()!)
}
}
}
}
}
}
我现在的结论是,它只适用于具有固定高度的子视图。仅此问题就阻止了 SwiftUI 为生产做好准备。LazyVStack
有没有人解决这个问题?
APPLE 的回应(2021 年 7 月 27 日):
“在您的 Mac 目标上,这一切都有效,但我看到 iOS 上存在滚动问题。这个问题绝对是 iOS 上 SwiftUI 的错误。我建议不要重写您的应用程序,而是将 UIViewRepresentable 用于 UIScrollView(或者实际上 UITable / UICollection View 在这里最有意义)。如果使用可重用的视图(如表或集合),这些问题几乎肯定会消失。你不需要重写你的应用,但如果这个问题阻止了发布,你应该添加一个 UIViewRepresentable。
答:
在 macOS 12.beta、Xcode 13.beta、目标 ios 15 和 macCatalyst 上没有任何问题。在 ios15 设备和 macOS 12 上测试。我也尝试使用 10000,效果很好。也许您的问题发生在较旧的 ios 和 macos 上。您可能对被高频@StateObject更新淹没的 Swift UI 感兴趣? 代码在 iOS14 上挣扎,但在 iOS15 上却没有。
您可以尝试其他方法来查看是否可以提高性能,例如:
ForEach(items.indices, id: \.self) { index in
Text(items[index]).background(colors.randomElement()!)
}
或
ForEach(Array(items.enumerated()), id: \.0) { index, item in
Text(item).background(colors.randomElement()!)
}
评论
在 iOS 15 中,此错误似乎已修复。
在 iOS 14 中,我建议在 VStack 中显示前 n 个项目(足以用缓冲区填充屏幕高度),其余项目在 LazyVStack 中显示。我发现在大多数情况下,这消除了抖动。
ScrollView {
VStack(spacing: 10) {
ForEach(items.prefix(10)) { item in
Text(item.text)
.background(colors.randomElement()!)
}
}
LazyVStack(spacing: 10) {
ForEach(items.dropFirst(10)) { item in
Text(item.text)
.background(colors.randomElement()!)
}
}
}
}
}
评论
对我来说,抖动是由于将修饰符附加到视图中引起的(因此它在集合中的每个项目上运行)。即使钩子在后台线程中运行,即使它根本没有做任何事情,也会发生抖动。onAppear
ForEach
没有 100% 修复它,但我的解决方案是只将修饰符添加到真正需要它的元素中。就我而言,我用于连续滚动(分页)。通过仅添加到列表中的第 n 项,能够在接近列表末尾时将抖动大大减少到一个小点。onAppear
onAppear
onAppear
这是一篇关于如何有条件地应用修饰符的好文章。
不确定这是否会帮助那些还不能将他们的最低版本升级到 iOS 15 的人,但希望它确实如此!
评论
offset
是一个不稳定的标识符。请看这个答案。如果相关,请告诉我。List
List
List
List
CACollectionView