在没有按钮的 SwiftUI 中呈现新视图

Posted

技术标签:

【中文标题】在没有按钮的 SwiftUI 中呈现新视图【英文标题】:Presenting New Views in SwiftUI Without a Button 【发布时间】: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 不提供任何方式来预加载其堆栈,而不仅仅是根视图。确实很郁闷。 【参考方案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 开始,➝ .presentationModal 已被弃用。

别担心! .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 本质上是按钮,所以它们需要一个点击手势才能发生任何事情。

以上是关于在没有按钮的 SwiftUI 中呈现新视图的主要内容,如果未能解决你的问题,请参考以下文章

登录后如何在 SwiftUI 中显示新视图

SwiftUI - 通过 ContextMenu 呈现模态

如何将关闭按钮从 swiftui 视图的主结构(由 uihostingviewcontroller 呈现)分离到它自己的结构?

为啥即使发布者发出一个值,我的视图也没有在 SwiftUI 中呈现

如何在基于 SwiftUI 的 iOS 应用中呈现连续视图?

在 swiftUI 中是不是可以使用按钮在屏幕上添加新视图?