SwiftUI NavigationLink:成功运行帐户创建代码后导航到目标视图

Posted

技术标签:

【中文标题】SwiftUI NavigationLink:成功运行帐户创建代码后导航到目标视图【英文标题】:SwiftUI NavigationLink: Navigate to a destination view AFTER running account creation code successfully 【发布时间】:2019-08-28 18:00:53 【问题描述】:

我想运行帐户创建逻辑,然后如果成功,则转换到目标视图。否则,我将提供错误表。 NavigationLink 立即转换到点击的目标视图。

如果我使用 isActive 重载和一个空字符串作为文本创建一个虚拟 NavigationLink(这会创建一个零帧视图),我可以让它工作。然后,我使用向用户提供的 Button 切换 isActive 属性,该按钮首先运行帐户创建逻辑,并在链的末尾将 NavigationLink 切换为活动状态。我在 NavigationView 中。

        @State private var isActive: Bool = false

        NavigationView 

            // Name, Email, Password Textfields here

            // Button to run account creation logic:

            Button(action: 
                // Account creation promise chain here, then...
                self.isActive.toggle()
            ) 
                Text("Create Account")
            

            // Phantom navigation link:

            NavigationLink("", destination: VerifyEmailView(email: email), isActive: self.$isActive)

        

有没有更好的方法来做到这一点?从按钮触发运行帐户创建逻辑,然后激活虚拟导航链接以转换到下一个屏幕,这似乎是一种不好的做法。

【问题讨论】:

我的答案(以及同一个问题中的另一个答案)可能很有趣:***.com/a/57717462/1311272 谢谢 Sajjon,这两个答案都很有趣。我正在尝试使用最 SwiftUI-y 的方式,所以@kontiki 的回答很有帮助,谢谢你指点我。使用 SwiftUI 对我来说最困难的部分是 1)在逻辑成功运行后在同一个 NavigationView“堆栈”中转换(即创建帐户以验证电子邮件视图),以及 2)转换到新的 NavigationView“堆栈”(即成功登录到带有自己的 NavigationView“堆栈”的主视图)。 一般听起来你很难思考异步?从您的代码看来,您认为 VerifyEmail 的 NavigationLink 将在创建帐户后执行。事实并非如此,这与视图的定位有关,而不是执行顺序。 你知道如何使用 UIKIT 做到这一点吗? 是的,这就是我遇到的困难 - 如何让 NavigationLink 仅在帐户创建承诺链完成后才能激活。我在 UIKit 中构建了它,我正在尝试将所有视图和转换转换为 SwiftUI。现在我使用 PromiseKit 并在最后一个块中将新的视图控制器推送到堆栈上。我很难理解如何完成相同的异步工作,然后只有在成功的情况下才推送新的控制器。 【参考方案1】:

有一种非常简单的方法可以处理您的视图状态和NavigationLinks。 您可以通过将tag 绑定到它来通知您的NavigationLink 自行执行。 然后您可以设置-取消设置标签并控制您的NavigationLink

struct SwiftView: View 
@State private var actionState: Int? = 0

var body: some View 

    NavigationView 
                VStack 
                    NavigationLink(destination: Text("Destination View"), tag: 1, selection: $actionState) 
                        EmptyView()
                    


                    Text("Create Account")
                        .onTapGesture 
                            self.asyncTask()
                    
                
            
    

func asyncTask() 
    //some task which on completion will set the value of actionState
    self.actionState = 1

这里我们已经将actionStateNavigationLink 绑定在一起,因此每当actionState 的值发生变化时,它将与与我们的NavigationLink 关联的tag 进行比较。

在您将actionState 的值设置为等于与我们的NavigationLink 关联的tag 之前,您的目标视图 将不可见。

这样,您可以创建任意数量的NavigationLinks,并且可以通过更改一个Bindable 属性来控制它们。

谢谢,希望对你有帮助。

【讨论】:

提示:使用nil 作为动作状态的初始值是行不通的。在我的情况下,导航链接仍然立即执行。【参考方案2】:

以 Mohit 的回答为基础,使用封装屏幕状态的枚举使 Swifty 变得更加快捷:


enum ActionState: Int 
    case setup = 0
    case readyForPush = 1


struct SwiftView: View 
    @State private var actionState: ActionState? = .setup

    var body: some View 

        NavigationView 
                VStack 
                    NavigationLink(destination: SomeView, tag: .readyForPush, selection: $actionState) 
                        EmptyView()
                    


                    Text("Create Account")
                        .onTapGesture 
                            self.asyncTask()
                    
                
            
       

func asyncTask() 
    //some task which on completion will set the value of actionState
    self.actionState = .readyForPush

【讨论】:

【参考方案3】:

您可以将目标视图包装在惰性视图中以防止立即调用。这是一个例子:

struct LazyView<Content: View>: View 
    let build: () -> Content
    init(_ build: @autoclosure @escaping () -> Content) 
        self.build = build
    
    var body: Content 
        build()
    

最终,像这样调用它:

NavigationLink(destination: LazyView(Text("Detail Screen")))//your code

我写了一篇完整的博客文章,涵盖了 SwiftUI 中 NavigationLinks 的其他一些缺陷。 Refer here.

【讨论】:

以上是关于SwiftUI NavigationLink:成功运行帐户创建代码后导航到目标视图的主要内容,如果未能解决你的问题,请参考以下文章

NavigationLink 中的 SwiftUI 按钮

SwiftUI:NavigationLink 奇怪的行为

SwiftUI 上的 NavigationLink 两次推送视图

SwiftUI:NavigationLink 内的水平 ScrollView 会中断导航

有没有办法向 NavigationLink 添加额外的功能? SwiftUI

无法单击列表中的 NavigationLink (SwiftUI)