我正在实现名为MenuItem
的非常自定义NavigationLink,并希望在整个项目中重复使用它。这是一个符合View
并实现包含var body : some View
的{{1}}的结构。
我需要以某种方式将NavigationLink
所呈现的视图存储在NavigationLink
的正文中,但尚未这样做。
我在MenuItem
的正文中将destinationView
定义为MenuItem
,并尝试了两个初始化方法:
这似乎太简单了:
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...
}
}
->错误:无法将类型为“ V”的值分配为类型为“某些视图”。
最终尝试:
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...
}
}
->错误::无法将“视图”类型的值分配给“某些视图”。
我希望有人能帮助我。如果NavigationLink可以接受某些View作为参数,则必须有一种方法。 谢谢; D
答案 0 :(得分:13)
总结一下,我在这里阅读的所有内容以及适用于我和 iOS14 的解决方案:
<nav id="my-menu">
<ul>
<li><a href="/">Home</a></li>
<li><a href='/'>About us</span>
<ul>
<li><a href="/about/history">History</a></li>
<li><a href="/about/team">The team</a></li>
<li><a href="/about/address">Our address</a></li>
</ul>
</li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
这不仅允许您将简单的struct ContainerView<Content: View>: View {
let content: Content
init(@ViewBuilder content: @escaping () -> Content) {
self.content = content()
}
var body: some View {
// Do something with `content`
}
}
放入其中,而且还得益于View
,使用@ViewBuilder
和if-else
块:
switch-case
答案 1 :(得分:6)
您可以这样创建自定义视图:
struct ENavigationView<Content: View>: View {
let viewBuilder: () -> Content
var body: some View {
NavigationView {
VStack {
viewBuilder()
.navigationBarTitle("My App")
}
}
}
}
struct ENavigationView_Previews: PreviewProvider {
static var previews: some View {
ENavigationView {
Text("Preview")
}
}
}
使用:
struct ContentView: View {
var body: some View {
ENavigationView {
Text("My Text")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
答案 2 :(得分:1)
您应该将通用参数作为MenuItem
的一部分:
struct MenuItem<Content: View>: View {
private var destinationView: Content
init(destinationView: Content) {
self.destinationView = destinationView
}
var body : some View {
// ...
}
}
答案 3 :(得分:1)
您可以按如下所示将NavigationLink(或任何其他视图小部件)作为变量传递给子视图:
import SwiftUI
struct ParentView: View {
var body: some View {
NavigationView{
VStack(spacing: 8){
ChildView(destinationView: Text("View1"), title: "1st")
ChildView(destinationView: Text("View2"), title: "2nd")
ChildView(destinationView: ThirdView(), title: "3rd")
Spacer()
}
.padding(.all)
.navigationBarTitle("NavigationLinks")
}
}
}
struct ChildView<Content: View>: View {
var destinationView: Content
var title: String
init(destinationView: Content, title: String) {
self.destinationView = destinationView
self.title = title
}
var body: some View {
NavigationLink(destination: destinationView){
Text("This item opens the \(title) view").foregroundColor(Color.black)
}
}
}
struct ThirdView: View {
var body: some View {
VStack(spacing: 8){
ChildView(destinationView: Text("View1"), title: "1st")
ChildView(destinationView: Text("View2"), title: "2nd")
ChildView(destinationView: ThirdView(), title: "3rd")
Spacer()
}
.padding(.all)
.navigationBarTitle("NavigationLinks")
}
}
答案 4 :(得分:1)
我真的很难使我的作品扩展为View
。请参见here。有关如何调用它的完整详细信息。
View
的扩展名(使用泛型)-请记住import SwiftUI
:
extension View {
/// Navigate to a new view.
/// - Parameters:
/// - view: View to navigate to.
/// - binding: Only navigates when this condition is `true`.
func navigate<SomeView: View>(to view: SomeView, when binding: Binding<Bool>) -> some View {
modifier(NavigateModifier(destination: view, binding: binding))
}
}
// MARK: - NavigateModifier
fileprivate struct NavigateModifier<SomeView: View>: ViewModifier {
// MARK: Private properties
fileprivate let destination: SomeView
@Binding fileprivate var binding: Bool
// MARK: - View body
fileprivate func body(content: Content) -> some View {
NavigationView {
ZStack {
content
.navigationBarTitle("")
.navigationBarHidden(true)
NavigationLink(destination: destination
.navigationBarTitle("")
.navigationBarHidden(true),
isActive: $binding) {
EmptyView()
}
}
}
}
}
答案 5 :(得分:1)
接受的答案很好也很简单。 iOS 14 + macOS 11 的语法变得更加清晰:
struct ContainerView<Content: View>: View {
@ViewBuilder var content: Content
var body: some View {
content
}
}
然后继续这样使用:
ContainerView{
...
}
答案 6 :(得分:0)
Apple使用函数构建器的方式是,有一个预定义的视图构建器,称为ViewBuilder,它使MenuItem的init方法成为您的最后一个参数,或仅将其作为参数
...., @ViewBuilder builder: @escaping () -> Content)
将其分配给定义如下的属性
let viewBuilder: () -> Content
然后要在其中输出View的地方,只需调用类似的函数
HStack {
viewBuilder()
}
那你就可以做
MenuItem {
Image("myImage")
Text("My Text")
}
这将使您最多传递10个视图并在条件等条件下使用,因此,如果您希望限制更多,则必须定义自己的函数生成器。我还没有这样做,所以您将不得不在Google上搜索。