繁体   English   中英

如何使用 SwiftUI 以编程方式转换视图?

[英]How to transition Views programmatically using SwiftUI?

我想在登录成功时向用户显示另一个视图,否则留在该视图上。 我已经通过执行转场使用 UIKit 做到了这一点。 SwiftUI 中有这样的选择吗?

NavigationButton 解决方案不起作用,因为我需要在转换到另一个视图之前验证用户输入。

Button(action: {
    let authService = AuthorizationService()
    let result = authService.isAuthorized(username: self.username, password: self.password)
    if(result == true) {
        print("Login successful.")
        // TODO: ADD LOGIC
        *** HERE I WANT TO PERFORM THE SEGUE ***

        presentation(MainView)
    } else {
        print("Login failed.")
    }
}) {
    Text("Login")
}

Xcode 11 测试版 5。

NavigationDestinationLinkNavigationButton已被弃用并由NavigationLink取代。

这是以编程方式将视图推送到 NavigationView 的完整工作示例。

import SwiftUI
import Combine


enum MyAppPage {
    case Menu
    case SecondPage
}

final class MyAppEnvironmentData: ObservableObject {
    @Published var currentPage : MyAppPage? = .Menu
}

struct NavigationTest: View {

    var body: some View {
        NavigationView {
            PageOne()
        }
    }
}


struct PageOne: View {
    @EnvironmentObject var env : MyAppEnvironmentData


    var body: some View {
        let navlink = NavigationLink(destination: PageTwo(),
                       tag: .SecondPage,
                       selection: $env.currentPage,
                       label: { EmptyView() })

        return VStack {
            Text("Page One").font(.largeTitle).padding()

            navlink
            .frame(width:0, height:0)

            Button("Button") {
                self.env.currentPage = .SecondPage
            }
            .padding()
            .border(Color.primary)

        }
    }

}


struct PageTwo: View {

    @EnvironmentObject var env : MyAppEnvironmentData

    var body: some View {
        VStack {
            Text("Page Two").font(.largeTitle).padding()

            Text("Go Back")
            .padding()
            .border(Color.primary)
            .onTapGesture {
                self.env.currentPage = .Menu
            }
        }.navigationBarBackButtonHidden(true)
    }
}

#if DEBUG
struct NavigationTest_Previews: PreviewProvider {
    static var previews: some View {
        NavigationTest().environmentObject(MyAppEnvironmentData())
    }
}
#endif

请注意, NavigationLink实体必须存在于视图主体内。 如果您有触发链接的按钮,您将使用 NavigationLink 的标签。 在这种情况下,NavigationLink 通过将其框架设置为 0,0 来隐藏,这是一种黑客行为,但我目前不知道更好的方法。 .hidden() 没有同样的效果。

根据响应,您可以像下面那样做(它像 Playground 一样打包以便于测试:

import SwiftUI
import Combine
import PlaygroundSupport


struct ContentView: View {
    var body: some View {
        NavigationView {
            MainView().navigationBarTitle(Text("Main View"))
        }
    }
}

struct MainView: View {
    let afterLoginView = DynamicNavigationDestinationLink(id: \String.self) { message in
        AfterLoginView(msg: message)
    }

    var body: some View {
        Button(action: {
            print("Do the login logic here")
            self.afterLoginView.presentedData?.value = "Login successful"
        }) {
            Text("Login")
        }
    }
}

struct AfterLoginView: View {
    let msg: String

    var body: some View {
        Text(msg)
    }
}

PlaygroundPage.current.liveView = UIHostingController(rootView: ContentView())

虽然这会奏效,但我认为,从架构的角度来看,您尝试将“命令式编程”范式推入 SwiftUI 的响应式逻辑中。 我的意思是,我宁愿将登录逻辑封装到ObjectBinding类中,并带有公开的isLoggedin属性来实现它,并使 UI 对当前状态(由isLoggedin表示)做出反应。

这是一个非常高级的示例:

struct MainView: View {
    @ObjectBinding private var loginManager = LoginManager()

    var body: some View {
        if loginManager.isLoggedin {
            Text("After login content")
        } else {
            Button(action: {  
                 self.loginManager.login()
            }) {
                 Text("Login")
            }
        }
    }
}

我使用 Bool 状态进行登录转换,它看起来非常流畅。

struct ContentView: View {
    @State var loggedIn = false
    
    var body: some View {
        VStack{
            if self.loggedIn {
                Text("LoggedIn")
                Button(action: {
                    self.loggedIn = false 

                }) {
                    Text("Log out")
                }
            } else {
                LoginPage(loggedIn: $loggedIn)
            }
        }
    }
}

也可以通过编程方式完成,例如:

let vc = self.storyboard?.instantiateViewController(withIdentifier: "TheTargetViewController")
                            self.present(vc!, animated: true, completion: nil)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM