【问题标题】:Content with variable height in a LazyVStack inside a ScrollView causes stuttering / jumpingScrollView 内的 LazyVStack 中具有可变高度的内容导致口吃/跳跃
【发布时间】:2021-09-28 05:52:17
【问题描述】:

XCode 版本 13.0 测试版 (13A5155e) & 针对 iOS 14 或 15

我的目标是在 SwiftUI 中创建一个聊天视图。这需要创建一个具有不同高度内容的 ScrollView。

经过大量调试,我确定如果您在 ScrollView 中有没有固定高度的视图,当您滚动到视图顶部时它会卡顿。

––––

项目: Download this project and try for yourself

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 的一个错误。我建议您不要重写您的应用程序,而是为您的 UIScrollView 使用 UIViewRepresentable(或者实际上UITable / UICollection View 在这里最有意义)。如果您使用可重复使用的视图,例如表格或集合,这些问题几乎肯定会消失。您不需要重写您的应用程序,但您应该添加 UIViewRepresentable 如果此问题正在阻止发布。”

【问题讨论】:

  • offset 是一个不稳定的标识符。见this answer。让我知道它是否相关。
  • 这并不能解决口吃问题。不过你是对的,我已经更新了代码以反映更好的方法。
  • 也许你可以只在 UIKit 中实现这个屏幕? SwiftUI 还是很新的,可能还需要几年的时间才能在可靠性和稳定性方面接近 UIKit。
  • 是的,这就是后备。这是应用程序的主要视图之一——聊天视图。在 UIKit 中重写这整个事情将是一项艰巨的任务,但我希望 SwiftUI 能够完成它。这实际上是唯一阻止它的事情 :( 另一种选择是我可以使用 List 并失去平滑过渡,使用 VStack 并且一次不会显示超过 30 个项目,或者在 UIKit 中重写它。我会可能首先重新审视List 方法。
  • 我遇到了几乎相同的问题,Apple 的回答令人失望。如果你像我一样选择List,你可能会遇到这个:stackoverflow.com/questions/68383332/…——所以尽早测试是否有泄漏。 ;) 仍然在我的清单上尝试使用List,但要使用有限数量的物品以避免泄漏。或尝试其他替代方案,例如CACollectionView。请更新您的进度!感谢分享!

标签: ios swift swiftui uiscrollview


【解决方案1】:

在 macos 12.beta、xcode 13.beta、target ios 15 和 macCatalyst 上运行没有任何问题。在 ios15 设备和 macos 12 上测试。我也尝试使用 10000,效果很好。也许您的问题发生在较旧的 ios 和 macos 上。您可能对 Swift UI overwhelmed by high-frequency @StateObject updates? 感兴趣,那里的代码在 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,它仍然发生在设备和模拟器上。我有 iPhone 11 Pro Max 和相当快的 iMac,所以我认为性能不是这里的问题。您是否尝试过多次洗牌并向下拖动?对我来说几乎每次都会发生。
猜你喜欢
  • 1970-01-01
  • 2016-10-01
  • 2014-08-15
  • 1970-01-01
  • 2021-04-30
  • 2015-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多