【问题标题】:SwiftUI ForEach not correctly updating in scrollviewSwiftUI ForEach 在滚动视图中未正确更新
【发布时间】:2020-04-06 12:33:26
【问题描述】:

我有一个 SwiftUI ScrollView,里面有一个 HStack 和一个 ForEach。 ForEach 是由 ObservableObject 的 Published 变量构建的,因此在添加/删除/设置项目时,它将在视图中自动更新。但是,我遇到了多个问题:

  1. 如果数组一开始是空的,然后添加了项目,则不会显示它们。
  2. 如果数组中有一些项目,我可以添加一项,它会显示,但添加更多则不会。

如果我只有一个带有 ForEach 的 HStack,上述问题都不会发生。一旦它在 ScrollView 中,我就会遇到问题。

下面是可以粘贴到 Xcode SwiftUI Playground 中以演示问题的代码。在底部,您可以取消注释/注释不同的行以查看两个不同的问题。

如果您取消注释问题 1,然后单击任一按钮,您将只看到 HStack 更新,而不是 ScrollView 中的 HStack 即使您看到这些项目的 init print 语句。

如果您取消注释问题 2,然后单击任一按钮,您应该会在第二次单击后看到 ScrollView 更新,但如果您继续单击它不会更新 - 即使只有 HStack 会继续更新并初始化打印语句是 ScrollView 项目的输出。

import SwiftUI
import PlaygroundSupport
import Combine

final class Testing: ObservableObject {
    @Published var items: [String] = []

    init() {}

    init(items: [String]) {
        self.items = items
    }
}

struct SVItem: View {
    var value: String

    init(value: String) {
        print("init SVItem: \(value)")
        self.value = value
    }

    var body: some View {
        Text(value)
    }
}

struct HSItem: View {
    var value: String

    init(value: String) {
        print("init HSItem: \(value)")
        self.value = value
    }

    var body: some View {
        Text(value)
    }
}

public struct PlaygroundRootView: View {
    @EnvironmentObject var testing: Testing

    public init() {}

    public var body: some View {
        VStack{
            Text("ScrollView")
            ScrollView(.horizontal) {
                HStack() {
                    ForEach(self.testing.items, id: \.self) { value in
                        SVItem(value: value)
                    }
                }
                .background(Color.red)
            }
            .frame(height: 50)
            .background(Color.blue)
            Spacer()
            Text("HStack")
            HStack {
                ForEach(self.testing.items, id: \.self) { value in
                    HSItem(value: value)
                }
            }
            .frame(height: 30)
            .background(Color.red)
            Spacer()
            Button(action: {
                print("APPEND button")
                self.testing.items.append("A")
            }, label: { Text("APPEND ITEM") })
            Spacer()
            Button(action: {
                print("SET button")
                self.testing.items = ["A", "B", "C"]
            }, label: { Text("SET ITEMS") })
            Spacer()
        }
    }
}

// Present the view controller in the Live View window
PlaygroundPage.current.liveView = UIHostingController(
    // problem 1
    rootView: PlaygroundRootView().environmentObject(Testing())

    // problem 2
    // rootView: PlaygroundRootView().environmentObject(Testing(items: ["1", "2", "3"]))
)

这是一个错误吗?我错过了什么吗?我是 iOS 开发新手。我确实尝试在 DispatchQueue.main.async 中包装实际的项目设置/附加,但这并没有做任何事情。

另外,可能不相关,但如果您单击按钮足够多,应用程序似乎会崩溃。

【问题讨论】:

    标签: ios swiftui


    【解决方案1】:

    刚刚遇到同样的问题。解决了空数组检查和不可见的 HStack

    ScrollView(showsIndicators: false) {
        ForEach(self.items, id: \.self) { _ in
            RowItem()
        }
    
        if (self.items.count == 0) {
            HStack{
                Spacer()
            }
        }
    }
    

    【讨论】:

    • 它拯救了我的一天!谢谢!
    • 我也更喜欢这种黑客攻击,而不是在数组内具有假初始值的黑客攻击。谢谢:)
    【解决方案2】:

    已知ScrollView 的行为与观察到的空容器 - 它需要一些东西(初始内容)来计算初始大小,因此以下解决了您的代码行为

    @Published var items: [String] = [""]
    

    一般来说,在这种情况下,我更喜欢在数组中存储一些“易于检测的初始值”,当第一个“真实模型值”出现时将其删除,然后在最后一个消失时再次添加。希望这会有所帮助。

    【讨论】:

    • 不幸的是,这似乎不起作用。我在上面的代码中尝试过,仍然遇到与问题 2 相同的问题。
    • 嗯,我有 11.3,虽然它会显示在第二次点击按钮后添加/替换的第一个项目,但在那之后它不会做任何事情。
    • 我在 SO 上观察到对 Xcode 11.3 的几个主要抱怨,所以可能值得降级...我什至会对 11.1 说,因为 11.2 在 List 和 NavigationView 方面也有几个不好的问题。
    • 降级到 11.1 并且可以正常工作。仍然有一些怪癖,但它出现了!
    【解决方案3】:

    为了更好的可读性,也因为答案对我不起作用。我建议将@TheLegend27 的答案稍微修改如下:

    if self.items.count != 0 {
    
       ScrollView(showsIndicators: false) {
           ForEach(self.items, id: \.self) { _ in
               RowItem()
           }
       }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-06-11
      • 2021-12-29
      • 1970-01-01
      • 2016-03-19
      • 1970-01-01
      • 2021-05-02
      • 2021-02-17
      • 1970-01-01
      相关资源
      最近更新 更多