如何访问 SwiftUI 中的子视图? [英] How to access to the children views in SwiftUI?

查看:27
本文介绍了如何访问 SwiftUI 中的子视图?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究 SwiftUI,感觉它与 React 非常相似.刚才我在自定义一个 SwiftUI 的 Button 并且遇到了无法动态访问 Button 的子视图的问题以下代码是我要做的:

I'm working on the SwiftUI, and feeling it's very similar with React. Just now I'm customizing a Button of SwiftUI and have a problem which can't access to the children views of Button dynamically Following codes is what I'm going to do:

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")
  }
}

拜托,我的想法有误吗?

Please, do I have a wrong idea?


更新

取决于@graycampbell 的回答,我尝试如下

Depends on @graycampbell 's answer I tried as following

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 看起来和它本身一样好.但是此时我在使用中还有另一个编译错误.

So the FullButton looks well as itself. But I have another compile error in usage at this time.

VStack {
    FullButton(action: { print("touched") }) {
        Text("Fullbutton")
    }
}

错误是 引用初始化程序 'init(alignment:spacing:content:)' on 'VStack' requires that 'FullButton'符合视图".
这意味着 FullButton 现在还没有返回 body 吗?
我不知道为什么会这样,因为 FullButton 仍然扩展 View 类.
请让我知道该类型类的正确 body 定义是什么.

The error is Referencing initializer 'init(alignment:spacing:content:)' on 'VStack' requires that 'FullButton<Text>' conform to 'View'.
It means FullButton hasn't return the body now?
I'm not sure why it is because the FullButton still extends View class.
Please let me know what's the correct body definition of that type of class.

推荐答案

如果我正确理解您的问题,这就是您要找的:

This is what you're looking for, if I'm understanding your question correctly:

struct FullButton<Label>: View where Label: View {
    var action: () -> Void
    var label: () -> Label

    var body: some View {
        Button(action: self.action, label: self.label)
    }
}

这将允许您传递想要在按钮上显示的任何内容,这意味着您在此处拥有的代码现在可以工作了:

This would allow you to pass whatever content you want to be displayed on your button, meaning that the code you have here would now work:

FullButton(action: {
    print("touched")
}) {
    Text("Button")
}

更新

在多次查看您的问题后,我意识到您的困惑源于对创建普通 Button 时发生的事情的误解.

Update

After looking over your question several times, I've realized that your confusion is stemming from a misunderstanding of what is happening when you create a normal Button.

在下面的代码中,我创建了一个 Button.该按钮有两个参数 - actionlabel.

In the code below, I'm creating a Button. The button takes two arguments - action and label.

Button(action: {}, label: {
    Text("Button")
})

如果我们查看 Button 的文档,我们会看到它是这样声明的:

If we look at the documentation for Button, we see that it is declared like this:

struct Button<Label> where Label : View

如果我们再看初始化器,我们会看到:

If we then look at the initializers, we see this:

init(action: @escaping () -> Void, @ViewBuilder label: () -> Label)

actionlabel 都需要闭包.action 需要返回类型为 Void 的闭包,而 label 需要返回类型为 @ViewBuilder 的闭包标签.正如在 Button 的声明中所定义的,Label 是一个表示 View 的泛型,所以实际上,label 期望一个返回 View 的闭包.

Both action and label expect closures. action expects a closure with a return type of Void, and label expects a @ViewBuilder closure with a return type of Label. As defined in the declaration for Button, Label is a generic representing a View, so really, label is expecting a closure that returns a View.

这不是 Button 独有的.以HStack为例:

This is not unique to Button. Take HStack, for example:

struct HStack<Content> where Content : View

init(alignment: VerticalAlignment = .center, spacing: Length? = nil, @ViewBuilder content: () -> Content)

Content 在这里的作用与 LabelButton 中的作用相同.

Content serves the same purpose here that Label does in Button.

还有一点需要注意——当我们创建一个这样的按钮时......

Something else to note - when we create a button like this...

Button(action: {}) {
    Text("Button")
}

...我们实际上正在做与此相同的事情:

...we're actually doing the same thing as this:

Button(action: {}, label: {
    Text("Button")
})

在 Swift 中,当方法调用中的最后一个参数是闭包时,我们可以省略参数标签并将闭包附加到右括号的外面.

In Swift, when the last argument in a method call is a closure, we can omit the argument label and append the closure to the outside of the closing parenthesis.

在 SwiftUI 中,您不能将内容隐式传递给任何 View.View 必须在其初始值设定项中显式接受 @ViewBuilder 闭包.

In SwiftUI, you cannot implicitly pass content to any View. The View must explicitly accept a @ViewBuilder closure in its initializer.

因此,除非 FullButton 接受 @ViewBuilder 闭包,否则您不能将 @ViewBuilder 闭包传递给 FullButton作为其初始值设定项中的参数,如我的答案开头所示.

And so, you cannot pass a @ViewBuilder closure to FullButton unless FullButton accepts a @ViewBuilder closure as an argument in its initializer, as shown at the beginning of my answer.

这篇关于如何访问 SwiftUI 中的子视图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆