繁体   English   中英

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

我现在的结论是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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM