SwiftUI ForEach 未在滚动视图中正确更新 [英] SwiftUI ForEach not correctly updating in scrollview

查看:29
本文介绍了SwiftUI ForEach 未在滚动视图中正确更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a SwiftUI ScrollView with an HStack and a ForEach inside of it. The ForEach is built off of a Published variable from an ObservableObject so that as items are added/removed/set it will automatically update in the view. However, I'm running into multiple problems:

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

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

If I just have an HStack with a ForEach neither of the above problems occur. As soon as it's in a ScrollView I run into the problems.

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

Below is code that can be pasted into the Xcode SwiftUI Playground to demonstrate the problem. At the bottom you can uncomment/comment different lines to see the two different problems.

如果您取消对问题 1 的注释,然后单击其中一个按钮,您将只看到 HStack 更新,而不会看到 ScrollView 中的 HStack 即使您看到这些项目的 init 打印语句.

If you uncomment problem 1 and then click either of the buttons you'll see just the HStack updating, but not the HStack in the ScrollView even though you see init print statements for those items.

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

If you uncomment problem 2 and then click either of the buttons you should see that after a second click the the ScrollView updates, but if you keep on clicking it will not update - even though just the HStack will keep updating and init print statements are output for the ScrollView items.

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 中包装实际的项目设置/附加,但这没有做任何事情.

Is this a bug? Am I missing something? I'm new to iOS development..I did try wrapping the actual items setting/appending in the DispatchQueue.main.async, but that didn't do anything.

另外,也许不相关,但如果你足够多地点击按钮,应用程序似乎会崩溃.

Also, maybe unrelated, but if you click the buttons enough the app seems to crash.

推荐答案

刚遇到同样的问题.解决了空数组检查 &隐形 HStack

Just ran into the same issue. Solved with empty array check & invisible HStack

ScrollView(showsIndicators: false) {
    ForEach(self.items, id: \.self) { _ in
        RowItem()
    }

    if (self.items.count == 0) {
        HStack{
            Spacer()
        }
    }
}

这篇关于SwiftUI ForEach 未在滚动视图中正确更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆