簡體   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