SwiftUI - 按钮 - 如何将函数请求传递给父级

问题描述 投票:0回答:2

如何让按钮执行在其“父”视图中触发功能的操作?我正在尝试重构我的代码,使组件尽可能小。

在这种情况下,按钮执行一些任务,但其中之一是运行一个函数:

Button(
 action: {
  self.setViewBackToNil()
 }){
  Text("Button")
}

// which triggers a function
func setViewBackToNil(){
 self.userData.image = nil
 self.isProcessing = false
 .... etc
}

现在,如果我将按钮变成它自己的视图,我将无法传递 self.setViewBackToNil,因为它包含在父级的结构中。

有没有办法让组件触发其父组件中的函数?

button swiftui
2个回答
96
投票

有关闭包及其使用方法的最佳示例可以在官方 swift 文档中找到。

这是一个关于如何将闭包传递给子视图然后调用父视图的函数的小示例:

struct ChildView: View {
    var function: () -> Void
    
    var body: some View {
        Button(action: {
            self.function()
        }, label: {
            Text("Button")
        })
    }
}

struct ParentView: View {
    var body: some View {
        ChildView(function: { self.fuctionCalledInPassedClosure() })
    }
    
    func fuctionCalledInPassedClosure() {
        print("I am the parent")
    }
}

我希望这有帮助!

传递一个函数

这是一个传递函数的示例:

struct ChildView: View {
    var function: () -> Void
    
    var body: some View {
        Button(action: {
            self.function()
        }, label: {
            Text("Button")
        })
    }
}

struct ParentView: View {
    var body: some View {
        ChildView(function: self.passedFunction)
    }
    
    func passedFunction() {
        print("I am the parent")
    }
}

传递带参数的函数

struct ChildView: View {
    var myFunctionWithParameters: (String, Int) -> Void
    
    var body: some View {
        Button(action: {
            self.myFunctionWithParameters("parameter", 1)
        }, label: {
            Text("Button")
        })
    }
}

struct ParentView: View {
    var body: some View {
        ChildView(myFunctionWithParameters: self.passedFunction)
    }
    
    func passedFunction(myFirstParameter: String, mySecondParameter: Int) {
        print("I am the parent")
    }
}

0
投票

请注意,这样做会破坏 swift UI 检查 UI 更新之间相等性的能力,并且会一直更新您的视图。

这是因为没有用于闭包的比较器。

因此,当性能对您的孩子的观点至关重要时,您可以这样做:

(已接受答案的示例)

struct ChildView: View & Equatable {
    var function: () -> Void
    
    var body: some View {
        Button(action: {
            self.function()
        }, label: {
            Text("Button")
        })
    }

    func ==(lhs: ChildView, rhs: ChildView) -> Bool {
        // here you can compare your views property yourself
        // In this case there is nothing to compare so we might give
        // true always
        true
    }
}

struct ParentView: View {
    var body: some View {
        ChildView(function: { self.fuctionCalledInPassedClosure() })
           .equatable()
    }
    
    func fuctionCalledInPassedClosure() {
        print("I am the parent")
    }
}

我添加的是对 Equatable 协议的一致性,并添加了一个比较器函数来告诉 swift UI 我的视图是否已更改。 在我们的例子中,除了回调之外没有其他属性。 您还必须告诉 swift UI 您的视图是 Equatable 视图。 因此,在您的 ParentView 中添加一个

.equatable()

如果添加调试打印,您将看到差异。

    var body: some View {
        Self._printChanges()
        return Button(action: {
            self.function()
        }, label: {
            Text("Button")
        })
    }
© www.soinside.com 2019 - 2024. All rights reserved.