Appleは、SwiftUIでUIViewController
を使用することをやめることを奨励していますが、ビューコントロールを使用しないと、少し無力な気がします。 ViewModel
にイベントを発行する、ある種のView
を実装できる。
ViewModel:
public protocol LoginViewModel: ViewModel {
var onError: PassthroughSubject<Error, Never> { get }
var onSuccessLogin: PassthroughSubject<Void, Never> { get }
}
ビュー:
public struct LoginView: View {
fileprivate let viewModel: LoginViewModel
public init(viewModel: LoginViewModel) {
self.viewModel = viewModel
}
public var body: some View {
NavigationView {
MasterView()
.onReceive(self.viewModel.onError, perform: self.handleError(_:))
.onReceive(self.viewModel.onSuccessLogin, perform: self.handleSuccessfullLogin)
}
}
func handleSuccessfullLogin() {
//Push next screen
}
func handleError(_ error: Error) {
//show alert
}
}
SwiftUIを使用して、私は次の実装方法がわかりません。
また、私がより良い方法で私が欲しいものを実装する方法についてのアドバイスをいただければ幸いです。ありがとう。
pdate 1:アラートを表示できましたが、viewModelのコールバックで別のビューをプッシュする方法が見つかりません
@Bhodanが述べたように、状態を変更することでそれを行うことができます
EnvironmentObject with SwiftUIの使用
class UserData: ObservableObject, Identifiable {
let id = UUID()
@Published var firebase_uid: String = ""
@Published var name: String = ""
@Published var email: String = ""
@Published var loggedIn: Bool = false
}
loggedIn
プロパティは、ユーザーの変更がいつログインまたはログアウトするかを監視するために使用されます
@EnvironmentObject
ファイルにSceneDelegate.Swift
として追加すると、アプリのどこからでもアクセスできるようになりますclass SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
// Create the SwiftUI view that provides the window contents.
let userData = UserData()
let contentView = ContentView().environmentObject(userData)
// Use a UIHostingController as window root view controller.
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}
loggedIn
プロパティに変更を加えると、それにバインドされているすべてのUIがtrue/false値の変更に応答します。
@Bhodanが言及したように、これをビューに追加するだけで、その変更に応答します
struct LoginView: View {
@EnvironmentObject userData: UserData
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: ProfileView(), isActive: self.$userData.loggedin) {
Text("")
}.hidden()
}
}
}
}
回避策作成せずに追加空のビュー。
.disabled(true)
または.allowsHitTesting(false)
修飾子を使用して、NavigationLinkのタップを無効にすることができます。
欠点:デフォルトのボタンタップの強調表示が緩んでいます。
NavigationLink(destination: EnterVerificationCodeScreen(), isActive: self.$viewModel.verifyPinIsShowing) {
Text("Create an account")
}
.allowsHitTesting(false) // or .disabled(true)
.buttonStyle(ShadowRadiusButtonStyle(type: .dark, height: 38))