SwiftUI 发送按钮点击到子视图

Posted

技术标签:

【中文标题】SwiftUI 发送按钮点击到子视图【英文标题】:SwiftUI send button tap to subview 【发布时间】:2020-01-15 18:22:59 【问题描述】:

我有几个视图包含相同的按钮和一些不同的内容。因此,我创建了一个ContainerView,其中包含共享的Button 布局,并为通用ContentView 留出了空间。

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

使用 UIKit,我会在 ContainerView 中保存对 ContentView 的引用,并在按下按钮时调用它的函数。但是,因为 SwiftUI 将所有视图都作为结构体,所以 contentView 在放入 ContainerViewbody 时会被复制。因此引用和显示的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
    

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

【问题讨论】:

在一个视图中有一个@State 属性,并将其作为@Binding 传递给另一个视图。然后,您可以更改 Binding 值的值,这将在第一个视图中更新您的 State 值。 所以问题是我希望ContentView 指示重置功能的实现,而不是ContainerView。在此示例中,我有一个 int,但在我自己的项目中,绑定是一个具有多个属性的结构;每个不同的ContentView 都会重置一个不同的。 你尝试使用 reactive SwiftUIimperative UIKit-like 方式。相反,您需要修改 model,具体取决于哪个视图应该做出相应的反应并重建自身。 @Asperi,对,我想我的问题是reactive SwiftUI 完成此任务的方式是什么。看起来有些人在下面给出了一些有用的答案! 【参考方案1】:

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

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 重置计数时,绑定将更新孩子。

编辑:我看到您的 cmets 想要 ContentView 控制重置逻辑。如果尝试复制 NavigationLink 之类的功能,其中一个 isActive: 布尔值由系统在导航时设置然后重置?

在您的情况下,您可以尝试以下方法:

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 组件所显示的模式。

【讨论】:

啊,没想到 didSet。试图弄清楚我如何将绑定转换为执行一些代码。谢谢!

以上是关于SwiftUI 发送按钮点击到子视图的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI:如何在单击 ActionSheet 按钮时呈现新视图?

在没有按钮的 SwiftUI 中呈现新视图

即使没有“点击”,SwiftUI List ForEach 视图中的按钮也会触发?

如何在 SwiftUI 的新地图视图中制作可点击的图钉?

在 SwiftUI 中点击更改按钮背景颜色

SwiftUI - 如何关闭工作表视图,同时关闭该视图