SwiftUI:从另一个初始化程序调用它时,如何让我的闭包返回“内容”而不是“某些视图”?

Posted

技术标签:

【中文标题】SwiftUI:从另一个初始化程序调用它时,如何让我的闭包返回“内容”而不是“某些视图”?【英文标题】:SwiftUI: How do I make my closure return 'Content' instead of 'some View' when calling it from another initialiser? 【发布时间】:2020-03-22 17:45:26 【问题描述】:

我目前正在学习 SwiftUI,但遇到了问题。

在下面的代码中,我有两个初始化程序。第一个有效(假设我注释掉第二个足够长的时间来测试代码)。第二个没有。它会引发编译器错误,提示“无法将'some View'类型的值分配给'Content'类型。

我在这里做错了什么?我能够使用Infobox() Text("Some Text") 从结构外部成功调用第一个初始化程序,在我看来,这与我尝试从第二个初始化程序调用它时使用的语法完全相同。无论我用多少谷歌搜索,我似乎都无法弄清楚这一点。

非常感谢您提供的任何帮助。

struct Infobox<Content>: View where Content: View 

    let content: Content

    var body: some View 
        content
    

    init(@ViewBuilder _ content: @escaping () -> Content) 
        self.content = content()
    

    init(withHeader headerText: String, @ViewBuilder _ content: @escaping () -> Content) 
        self.init() 
            VStack(alignment: .leading) 
                Text(headerText)
                    .font(.headline)
                
                content()
            
        
    

【问题讨论】:

【参考方案1】:

你的意思大概是这样的:

init<T: View>(withHeader headerText: String, @ViewBuilder _ content: @escaping () -> T) 
    where Content == VStack<TupleView<(Text, T)>> 
    self.init 
        VStack(alignment: .leading) 
            Text(headerText)
                .font(.headline)
            content()
        
    

此初始化程序创建的视图将始终采用以下形式(并且是)

InfoBox<VStack<TupleView<(Text, SomeOtherView)>>>

换句话说,这个初始化决定Content 应该是什么。所以它只适用于InfoBoxes 和Content == ThatLongTypeName,因此有约束。

注意调用者可以指定SomeOtherView的类型,但那不是ContentContentVStack&lt;TupleView&lt;(Text, SomeOtherView)&gt;&gt;。因此,增加了一个额外的泛型参数,并改变了闭包返回类型。


IMO,如果你这样做会简单得多:

struct Infobox<Content>: View where Content: View 

    let content: () -> Content
    let headerText: String

    var body: some View 
        VStack(alignment: .leading) 
            if !headerText.isEmpty 
                Text(headerText)
                    .font(.headline)
            
            content()
        
    

    // note the optional parameter here
    init(withHeader headerText: String = "", @ViewBuilder _ content: @escaping () -> Content) 
        self.content = content
        self.headerText = headerText
    

【讨论】:

非常感谢!您修改后的初始化程序确实起到了作用。但是为什么我的第一个初始化程序(没有 headerText)在没有所有额外内容的情况下工作,而第二个需要它? @Robin 您并不是说Content 应该是第一个初始化程序中的特定类型。 Content 可以是第一个初始化程序中的任何 View。但是,在第二个初始化程序中,您暗示 Content 必须是 InfoBox&lt;VStack&lt;TupleView&lt;(Text, SomeOtherView)&gt;&gt;&gt; 谢谢,有道理!

以上是关于SwiftUI:从另一个初始化程序调用它时,如何让我的闭包返回“内容”而不是“某些视图”?的主要内容,如果未能解决你的问题,请参考以下文章

如何在swiftUI的父视图中从另一个视图访问变量?

如何从另一个页面调用 useState?

SwiftUI |从另一个 SwiftUI 视图访问 PickerView 选择

如何正确初始化共享视图?

SwiftUI NavigationLink 如何到达另一个 SwiftUI 页面?

添加注释以从另一个视图映射