【问题标题】:Presenting New Views in SwiftUI Without a Button在没有按钮的 SwiftUI 中呈现新视图
【发布时间】:2019-06-05 16:22:21
【问题描述】:

所以我想使用 SwiftUI 呈现一个新视图,而无需用户点击按钮,因为 NavigationButton 可以使用它。这是一个例子

struct ContentView : View {

    var model: Model

    var body: some View {
        NavigationView {
            Text("Hello World")
        }.onAppear {
            if model.shouldPresent {
                // present a new view
            }
        }
    }
}

在onAppear 中,我想包含一些将新视图推送到导航堆栈的代码。

【问题讨论】:

  • 你有什么问题?
  • 您可以直接删除.onAppear { } 吗?或者你的意思是你想立即转到另一个场景?
  • @NRitH 直接转移到另一个场景。 onAppear 只是一个示例,因此我可以提供一个示例,而不必包含整个视图模型。
  • 从 Xcode 11 beta 4 开始,SwiftUI 的 NavigationView 不提供任何方式来预加载其堆栈,而不仅仅是根视图。确实很郁闷。

标签: ios swift swiftui


【解决方案1】:

这是一种将视图呈现为模态的方法。

struct PresentOnloadView: View {
    var body: some View {
        HStack {
            Text("Hey there")
            }
            .presentation(Modal(HelloView(), onDismiss: nil))
        }
}

struct HelloView: View {
    var body: some View {
        Text("Whats up! ?")
    }
}

同样,如果您想控制是否使用变量呈现,您可以执行以下操作..

struct PresentOnloadControlledView : View {
  @State var sayHello = false

    var body: some View {
        HStack {
                Text("What's up!")
            }
            .onAppear(perform: {
                // Decide whether to show another view or not here
                self.sayHello = true
            })
            .presentation(sayHello ? Modal(HelloView()) : nil)
    }
}

从版本 11.0 beta 4 开始,➝ .presentation 和 Modal 已被弃用。

别担心! .sheet 节省时间!

struct PresentOnloadControlledView : View {
  @State var sayHello = false

    var body: some View {
        HStack {
            Text("What's up!")
        }
        .onAppear(perform: {
            // Decide whether to show another view or not here
            self.sayHello = true
        })
        .sheet(isPresented: $sayHello) {
            HelloView()
        }
    }
}

【讨论】:

  • .presentation 效果很好,但是有没有办法在不将视图包装在 Model 中的情况下使用它?
  • .sheet 没有被我调用。嗯
【解决方案2】:

在你的视野中:

@State var present = true

var body: some View {
    NavigationLink(destination: DestinationView(), isActive: $present) {
        EmptyView()
    }
}

此代码在 NavigationLink 加载后立即显示 DestinationView。关键部分是isActive 参数,它以编程方式触发到另一个视图的转换。

你可以改写如下

@State var present = false

var body: some View {
    NavigationLink(destination: DestinationView(), isActive: $present) {
        Button { 
            present = true
        } label: { Text("Present") }
    }
}

手动创建导航按钮。

【讨论】:

    【解决方案3】:

    SwiftUI 2

    SwiftUI 2 / iOS 14 中的 Segue 等效项:

    • 显示(推送)
    struct ContentView: View {
        @State var showSecondView = false
    
        var body: some View {
            NavigationView {
                Text("First view")
                    .background(NavigationLink("", destination: Text("Second view"), isActive: $showSecondView))
            }
            .onAppear {
                DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                    showSecondView = true
                }
            }
        }
    }
    
    • 显示详细信息(替换)
    struct ContentView: View {
        @State private var showSecondView = false
    
        var body: some View {
            NavigationView {
                if showSecondView {
                    Text("Second view")
                } else {
                    Text("First view")
                }
            }
            .onAppear {
                DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                    showSecondView = true
                }
            }
        }
    }
    
    • 模态呈现
    struct ContentView: View {
        @State private var showSecondView = false
    
        var body: some View {
            NavigationView {
                Text("First view")
            }
            .sheet(isPresented: $showSecondView) {
                Text("Second view")
            }
            .onAppear {
                DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                    showSecondView = true
                }
            }
        }
    }
    
    • 全屏显示
    struct ContentView: View {
        @State private var showSecondView = false
    
        var body: some View {
            NavigationView {
                Text("First view")
            }
            .fullScreenCover(isPresented: $showSecondView) {
                Text("Second view")
            }
            .onAppear {
                DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                    showSecondView = true
                }
            }
        }
    }
    

    注意:我添加了DispatchQueue.main.asyncAfter(deadline: .now() + 1),以便您查看过渡。您可以将其移除,然后过渡将立即开始。

    【讨论】:

      【解决方案4】:

      您可以简单地将逻辑放在NavigationView 中。像这样:

      @State var x = true;
      
      var body : some View {
          NavigationView {
              if x {
                  Text("Hello")
                  Button(action: {
                      self.x = false;
                  }, label: { Text("Click Me") })
              } else {
                  Text("World")
              }
          }
      }
      

      【讨论】:

      • 据我所知,这实际上并没有将某些东西压入堆栈。你必须为你的整个导航堆栈拥有一个巨大的 if 链,这似乎有点疯狂。
      • 在这种情况下,Text("World") 是另一个视图。但是您可以将其更改为自定义视图。它将嵌入到body,但您可以更改动画类型,使其看起来就像发生了什么事。
      • 但它并没有推入导航堆栈,这比动画重要得多
      • NavigationViews 不会将视图推送到导航堆栈。它们充当NavigationLinks 的媒介,确实呈现新视图。尽管如此,NavigationLinks 本质上是按钮,所以它们需要一个点击手势才能发生任何事情。
      猜你喜欢
      • 2020-03-16
      • 1970-01-01
      • 2019-11-13
      • 2022-11-10
      • 1970-01-01
      • 1970-01-01
      • 2021-07-29
      • 1970-01-01
      相关资源
      最近更新 更多