我正在开发SwiftUI,感觉与React非常相似。刚才我正在自定义SwiftUI的Button并遇到无法动态访问Button的子视图的问题 以下代码是我要做的:
struct FullButton : View {
var action: () -> Void
var body: some View {
Button(action: action) {
// render children views here even what is that
children
}
}
}
和用法:
VStack {
FullButton(action: {
print('touched')
}) {
Text("Button")
}
}
请,我有一个错误的主意吗?
取决于我按照以下方式尝试过的@graycampbell的答案
struct FullButton<Label> where Label : View {
var action: () -> Void
var label: () -> Label
init(action: @escaping () -> Void, @ViewBuilder label: @escaping () -> Label) {
self.action = action
self.label = label
}
var body: some View {
Button(action: action, label: label)
}
}
因此FullButton
看起来很不错。但是我目前在使用中还有另一个编译错误。
VStack {
FullButton(action: { print("touched") }) {
Text("Fullbutton")
}
}
错误是Referencing initializer 'init(alignment:spacing:content:)' on 'VStack' requires that 'FullButton<Text>' conform to 'View'
。
这意味着FullButton
现在还没有返回body
?
我不确定为什么会这样,因为FullButton
仍然扩展了View
类。
请让我知道该类型的类的正确body
定义是什么。
答案 0 :(得分:2)
如果我正确理解了您的问题,这就是您要寻找的东西:
struct FullButton<Label>: View where Label: View {
var action: () -> Void
var label: () -> Label
var body: some View {
Button(action: self.action, label: self.label)
}
}
这将允许您传递想要在按钮上显示的任何内容,这意味着您在此处的代码现在可以使用:
FullButton(action: {
print("touched")
}) {
Text("Button")
}
在多次询问您的问题后,我意识到您的困惑是由于对创建普通Button
时正在发生的事情的误解。
在下面的代码中,我正在创建一个Button
。该按钮带有两个参数-action
和label
。
Button(action: {}, label: {
Text("Button")
})
如果我们查看Button
的文档,就会发现它是这样声明的:
struct Button<Label> where Label : View
如果我们再看一下初始化程序,我们会看到:
init(action: @escaping () -> Void, @ViewBuilder label: () -> Label)
action
和label
都期望关闭。 action
期望返回类型为Void
的闭包,label
期望返回类型为@ViewBuilder
的{{1}}闭合。如Label
的声明中所定义,Button
是表示Label
的泛型,因此,实际上View
期望闭包返回label
。 / p>
这并非View
所独有。以Button
为例:
HStack
struct HStack<Content> where Content : View
init(alignment: VerticalAlignment = .center, spacing: Length? = nil, @ViewBuilder content: () -> Content)
在这里的作用与Content
在Label
中的作用相同。
还有其他需要注意的地方-当我们创建这样的按钮时...
Button
...我们实际上正在执行以下操作:
Button(action: {}) {
Text("Button")
}
在Swift中,当方法调用中的最后一个参数是闭包时,我们可以省略参数标签,并将闭包附加到右括号的外面。
在SwiftUI中,您不能将内容隐式传递给任何Button(action: {}, label: {
Text("Button")
})
。 View
必须在其初始化程序中明确接受View
闭包。
因此,除非@ViewBuilder
在其初始值设定项中接受@ViewBuilder
闭包作为参数,否则您不能将FullButton
闭包传递给FullButton
,如我开头所示。答案。
答案 1 :(得分:0)
有一个ViewInspector库,该库使用Swift的反射从任何层次结构中提取SwiftUI视图。
let view = FullButton()
let button = try view.inspect().button()
let children = button.anyView().view(OtherView.Type)
// By the way, you can even tap the button programmatically:
try button.tap()