如何访问 SwiftUI 中的子视图?
How to access to the children views in SwiftUI?
我正在做 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
现在还没有returnbody
吗?
我不确定这是为什么,因为 FullButton
仍然扩展 View
class.
请告诉我 class.
类型的正确 body
定义是什么
如果我正确理解你的问题,这就是你要查找的内容:
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
期望 return 类型 Void
的闭包,label
期望 @ViewBuilder
类型 Label
的 return 闭包].正如在 Button
的声明中定义的那样,Label
是一个代表 View
的泛型,所以实际上,label
期望一个 return 是 [=32] 的闭包=].
这不是 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")
}
...我们实际上在做同样的事情:
Button(action: {}, label: {
Text("Button")
})
在Swift中,当方法调用的最后一个参数是闭包时,我们可以省略参数标签,将闭包附加到右括号外。
在 SwiftUI 中,您不能将内容隐式传递给任何 View
。 View
必须在其初始化程序中显式接受 @ViewBuilder
闭包。
因此,您不能将 @ViewBuilder
闭包传递给 FullButton
,除非 FullButton
在其初始化程序中接受 @ViewBuilder
闭包作为参数,如开头所示我的回答。
有一个 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()
我正在做 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
现在还没有returnbody
吗?
我不确定这是为什么,因为 FullButton
仍然扩展 View
class.
请告诉我 class.
body
定义是什么
如果我正确理解你的问题,这就是你要查找的内容:
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
期望 return 类型 Void
的闭包,label
期望 @ViewBuilder
类型 Label
的 return 闭包].正如在 Button
的声明中定义的那样,Label
是一个代表 View
的泛型,所以实际上,label
期望一个 return 是 [=32] 的闭包=].
这不是 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")
}
...我们实际上在做同样的事情:
Button(action: {}, label: {
Text("Button")
})
在Swift中,当方法调用的最后一个参数是闭包时,我们可以省略参数标签,将闭包附加到右括号外。
在 SwiftUI 中,您不能将内容隐式传递给任何 View
。 View
必须在其初始化程序中显式接受 @ViewBuilder
闭包。
因此,您不能将 @ViewBuilder
闭包传递给 FullButton
,除非 FullButton
在其初始化程序中接受 @ViewBuilder
闭包作为参数,如开头所示我的回答。
有一个 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()