开发者社区> 问答> 正文

SWIFUIForEach在滚动视图中未正确更新

我有一个具有HStack和ForEach的SwiftUI ScrollView。ForEach是由一个已发布的变量生成的,因此当项被添加/移除/设置时,它将在视图中自动更新。然而,我遇到了许多问题:

1.如果数组启动为空,然后添加项,则不会显示它们。 2.如果数组中有一些项,我可以添加一个项,它将显示这一点,但是添加更多项不会。 如果我只有一个带有ForEach的HStack,那么上面的任何一个问题都不会发生。一旦它出现在滚动视图中,我就会遇到问题。

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

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

如果取消注释问题2,然后单击任何一个按钮,那么在第二次单击ScrollView更新之后,您应该会看到,但是如果继续单击它不会更新--即使只是HStack将继续更新,init print语句也会输出到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"]))
)

这是bug吗?我是不是遗漏了什么?我是iOS开发的新手,我尝试过在DispatchQueue.main.异步文件中包装实际的项设置/附加项,但这没有起到任何作用。

另外,也可能是无关的,但是如果你点击的按钮足够多的话,应用程序就会崩溃。

展开
收起
游客5akardh5cojhg 2019-12-13 14:43:59 732 0
1 条回答
写回答
取消 提交回答
  • 这是众所周知的行为.ScrollView对于观察到的空容器-它需要一些东西(初始内容)来计算初始大小,因此下面的代码解决了您的代码行为

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

    通常,在这种情况下,我倾向于将一些“易于检测的初始值”存储在数组中,当第一个“真实模型值”出现并在最后一个消失时再次添加时,这个值将被删除。希望这会有帮助。

    2019-12-13 14:45:16
    赞同 展开评论 打赏
问答分类:
问答地址:
问答排行榜
最热
最新

相关电子书

更多
低代码开发师(初级)实战教程 立即下载
冬季实战营第三期:MySQL数据库进阶实战 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载