![](/img/trans.png)
[英]SwiftUI: Putting a LazyVStack or LazyHStack in a ScrollView causes stuttering (Apple bug??)
[英]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()!)
}
}
}
}
}
}
我现在的结论是LazyVStack
仅适用于具有固定高度的子视图。 仅此问题就会阻止 SwiftUI 投入生产。
有没有其他人解决过这个问题?
苹果的回应(2021 年 7 月 27 日):
"On your Mac target this all works but I see there are scrolling issues on iOS. This issue is definitely a bug with SwiftUI on iOS. I recommend that rather than rewrite your app you use a UIViewRepresentable for your UIScrollView (or actually UITable / UICollection View 在这里最有意义)。如果您使用可重复使用的视图,例如表格或集合,这些问题几乎肯定会消失。您不需要重写您的应用程序,但如果此问题是,您应该添加 UIViewRepresentable阻止释放。”
在 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()!)
}
}
}
}
}
对我来说,抖动是由于在ForEach
中的视图上附加了一个onAppear
修饰符(因此它在集合中的每个项目上运行)。 即使钩子在后台线程中运行并且即使它根本没有做任何事情,也会发生抖动。
没有 100% 修复它,但我的解决方案是只将onAppear
修饰符添加到真正需要它的元素中。 就我而言,我使用onAppear
进行连续滚动(分页)。 通过仅将onAppear
添加到列表中的第 n 个项目,能够大大减少接近列表末尾时的抖动。
这是一篇关于如何有条件地应用修饰符的好 文章。
不确定这是否会帮助那些还不能将他们的最低版本提升到 iOS 15 的人,但希望它可以!
在 macos 12.beta、xcode 13.beta、target 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()!)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.