XCode版本13.0测试版(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日(:
"在你的Mac目标上,这一切都有效,但我看到iOS上存在滚动问题。这个问题肯定是iOS上SwiftUI的一个错误。我建议您不要重写您的应用程序,而是使用UIViewRepresentable作为UIScrollView(或者实际上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测试版、xcode 13测试版、target ios 15和macCatalyst上运行时没有任何问题。在ios15设备和macos12上进行了测试。我也试过用10000,效果很好。也许你的问题发生在旧的ios和macos上。你可能对Swift UI感兴趣,它被频繁的@StateObject更新淹没了?其中代码在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()!)
}