首页 > 解决方案 > SwiftUI 发送按钮点击到子视图

问题描述

我有一些视图包含相同的按钮和一些不同的内容。正因为如此,我做了一个ContainerView容纳共享Button布局,并有空间容纳一个通用的ContentView.

我希望在点击按钮ContentView时做出响应ContainerView

使用 UIKit,我会持有对 in 的引用,ContentViewContainerView在按下按钮时在其上调用一个函数。但是,因为 SwiftUI 将所有视图都作为结构体,所以contentView在放入ContainerView's 时会复制 's body。因此参考和显示ContentView是不同的,我无法向子视图发送消息。

代码:

struct ContainerView: View {
    let contentView = ContentView()

    var body: some View {
        Group {
            /// When this button is tapped, I would like to send a message to the `ContentView`.
            Button(action: self.reset, label: { Text("RESET") })
            /// Unfortunately, this seemes to send a copy of the `contentView`. So I am unable to send the
            /// corrent struct a message.
            ///
            /// How can I send a subview a message from the superview?
            self.contentView
        }
    }

    func reset() {
        self.contentView.reset()
    }
}

struct ContentView: View {
    @State private var count: Int = 0

    var body: some View {
        Group {
            Text("Count: \(self.count)")
            Button(action: self.increment, label: { Text("Increment") })
        }
    }

    func increment() {
        self.count += 1
    }

    /// When this is called from the `ContainerView`, it is accessing a different ContentView 
    /// struct than is being displayed.
    func reset() {
        self.count = 0
    }
}

ContentView所以问题是:当点击中的按钮时,如何发送消息并运行一些代码ContainerView

标签: iosswiftswiftui

解决方案


与其尝试存储对子视图的引用,不如在它们之间进行绑定?在您的示例中,这可以通过绑定到计数来实现。

struct ContainerView: View {
    @State private var count = 0

    var body: some View {
        // Your Button wrapping the ContentView
        ContentView(count: $count)
    }

    func reset() {
        self.count = 0
    }
}


struct ContentView: View {
    @Binding var count: Int

    // ContentView's body
}

ContainerView重置计数时,绑定将更新孩子。

编辑:我看到您关于想要ContentView控制重置逻辑的评论。尝试复制某些功能,例如NavigationLinkisActive:在导航系统中设置布尔值然后重置的地方,怎么样?

在您的情况下,您可以尝试以下操作:

struct ContainerView: View {
    @State private var shouldReset: Bool = false

    var body: some View {
        // Your Button wrapping the ContentView
        ContentView(shouldReset: $shouldReset)
    }

    func reset() {
        self.shouldReset = true
    }
}


struct ContentView: View {
    @Binding var shouldReset: Bool {
        didSet {
            if shouldReset {
                // Call your reset logic here
            }
            shouldReset = false
        }
    }

    // ContentView's body
}

ContentView将知道更改,我们会将其视为单独的“状态”,然后在操作完成后重置该状态。

这可能不是理想的解决方案,但对我来说,它似乎复制了一些第一方 SwiftUI 组件显示的模式。


推荐阅读