ScrollView 内的 LazyVStack 中具有可变高度的内容会导致口吃/跳跃

chr*_*ysb 7 uiscrollview ios swift swiftui

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()!)
          }
        }
      }
    }
  }
}

Run Code Online (Sandbox Code Playgroud)

我现在的结论是LazyVStack仅适用于具有固定高度的子视图。仅此问题就阻止了 SwiftUI 的生产就绪。

有没有其他人解决过这个问题?

Apple 的回复(2021 年 7 月 27 日):

“在你的 Mac 目标上,这一切都有效,但我看到 iOS 上有滚动问题。这个问题绝对是 iOS 上 SwiftUI 的一个错误。我建议你不要重写你的应用程序,而是使用 UIViewRepresentable 作为你的 UIScrollView(或者实际上 UITable/UICollection View 在这里最有意义。如果您使用可重用的视图,例如表或集合,这些问题几乎肯定会消失。您不需要重写您的应用程序,但如果此问题是,您应该添加 UIViewRepresentable防止释放。”

wor*_*dog -1

在 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()!)
 }
Run Code Online (Sandbox Code Playgroud)

或者

 ForEach(Array(items.enumerated()), id: \.0) { index, item in
     Text(item).background(colors.randomElement()!)
 }
Run Code Online (Sandbox Code Playgroud)