[英]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。
NavigationDestinationLink
和NavigationButton
已被弃用并由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.