首页 > 解决方案 > 如何将一个 SwiftUI 视图作为变量传递给另一个视图结构

问题描述

我正在实现一个非常自定义的 NavigationLink MenuItem,并希望在整个项目中重用它。它是一个符合View并实现的结构,var body : some View其中包含一个NavigationLink. 我需要以某种方式存储应NavigationLink在正文中呈现的视图,MenuItem但尚未这样做。

destinationViewMenuItem's body 中定义为some View并尝试了两个初始化程序:

这似乎太容易了:

struct MenuItem: View {
    private var destinationView: some View

    init(destinationView: View) {
        self.destinationView = destinationView
    }

    var body : some View {
        // Here I'm passing destinationView to NavigationLink...
    }
}

--> 错误:协议“视图”只能用作通用约束,因为它具有自身或关联的类型要求。

第二次尝试:

struct MenuItem: View {
    private var destinationView: some View

    init<V>(destinationView: V) where V: View {
        self.destinationView = destinationView
    }

    var body : some View {
        // Here I'm passing destinationView to NavigationLink...
    }
}

--> 错误:无法将类型“V”的值分配给类型“某些视图”。

最后尝试:

struct MenuItem: View {
    private var destinationView: some View

    init<V>(destinationView: V) where V: View {
        self.destinationView = destinationView as View
    }

    var body : some View {
        // Here I'm passing destinationView to NavigationLink...
    }
}

--> 错误:无法将“视图”类型的值分配给“某些视图”类型。

我希望有一个人可以帮助我。如果 NavigationLink 可以接受某些 View 作为参数,则必须有一种方法。感谢:D

标签: swiftgenericsviewprotocolsswiftui

解决方案


总结一下我在这里读到的所有内容以及对我有用的解决方案:

struct ContainerView<Content: View>: View {
    @ViewBuilder var content: Content
    
    var body: some View {
        content
    }
}

这不仅允许您将简单View的 s 放入其中,而且由于@ViewBuilder, useif-elseswitch-caseblocks :

struct SimpleView: View {
    var body: some View {
        ContainerView {
            Text("SimpleView Text")
        }
    }
}

struct IfElseView: View {
    var flag = true
    
    var body: some View {
        ContainerView {
            if flag {
                Text("True text")
            } else {
                Text("False text")
            }
        }
    }
}

struct SwitchCaseView: View {
    var condition = 1
    
    var body: some View {
        ContainerView {
            switch condition {
            case 1:
                Text("One")
            case 2:
                Text("Two")
            default:
                Text("Default")
            }
        }
    }
}

奖励: 如果你想要一个贪婪的容器,它将占用所有可能的空间(与上面的容器相反,它只占用其子视图所需的空间)这里是:

struct GreedyContainerView<Content: View>: View {
    @ViewBuilder let content: Content
    
    var body: some View {
        Color.clear
            .overlay(content)
    }
}

如果您需要在视图中使用初始化程序,那么您也可以将@ViewBuilder其用于参数。如果您愿意,即使是多个参数:

init(@ViewBuilder content: () -> Content) {…}

推荐阅读