Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SwiftUI NavigationLink:成功运行帐户创建代码后导航到目标视图_Swiftui - Fatal编程技术网

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

SwiftUI NavigationLink:成功运行帐户创建代码后导航到目标视图,swiftui,Swiftui,我想运行帐户创建逻辑,然后,如果成功,转换到目标视图。否则,我将提供错误表。NavigationLink在点击时立即转换到目标视图 如果我使用isActive重载和空字符串作为文本创建phantom NavigationLink(它创建了一个零帧的视图),我就可以让它工作。然后,我使用一个按钮切换isActive属性,该按钮首先显示给运行帐户创建逻辑的用户,并在链的末尾将NavigationLink切换为active。我在导航视图中 @State private var isAc

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

如果我使用isActive重载和空字符串作为文本创建phantom NavigationLink(它创建了一个零帧的视图),我就可以让它工作。然后,我使用一个按钮切换isActive属性,该按钮首先显示给运行帐户创建逻辑的用户,并在链的末尾将NavigationLink切换为active。我在导航视图中

        @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)

        }

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

有一种非常简单的方法来处理视图的状态和
导航链接。
您可以通过将
标记
绑定到
导航链接
来通知它自己执行。 然后,您可以设置取消设置标记并控制
导航链接

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
}
}

在这里,我们将
actionState
NavigationLink
绑定,因此每当
actionState
的值发生变化时,它将与与
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
}
只有将
actionState
的值设置为与我们的
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
}
这样,您就可以创建任意数量的
NavigationLinks
,只需更改一个
Bindable
属性即可对其进行控制


谢谢,希望这能有所帮助。

以Mohit的答案为基础,使用封装屏幕状态的枚举来加快速度:


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
}

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

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

我已经写了一篇完整的博客文章,介绍了SwiftUI中导航链接的其他一些缺陷

我的答案(以及同一个问题中的另一个答案)可能很有趣:谢谢Sajjon,两个答案都很有趣。我想用最快捷的方式,所以@kontiki的回答很有帮助,谢谢你指点我。对于我来说,使用SwiftUI最困难的部分是1)在逻辑成功运行后在同一NavigationView“堆栈”内转换(即创建帐户以验证电子邮件视图),以及2)转换到新的NavigationView“堆栈”(即成功登录到具有自己NavigationView“堆栈”的主视图).一般来说,听起来您很难考虑异步?从您的代码来看,您认为VerifyEmail的NavigationLink将在创建帐户后执行。事实并非如此,这与视图的定位有关,而与执行顺序无关。你知道如何使用UIKIT来实现这一点吗?是的,这正是我很难做到的——如何让NavigationLink在帐户创建承诺链完成后才激活。我在UIKit中构建了它,我正在尝试将所有视图和转换转换为SwiftUI。现在我使用PromiseKit,在最后一个块中,将新的视图控制器推到堆栈上。如何完成相同的异步工作,然后在成功的情况下推送新控制器,这让我很为难。提示:使用
nil
作为操作状态的初始值是行不通的。在我的例子中,导航链接仍然立即执行。