完全移至其他视图,不允许在SwiftUI中返回

时间:2019-08-29 13:28:15

标签: ios swift swiftui

我正在用SwiftUI开发一个具有两个视图的简单iOS应用:LogInView()HomeView()

我想要的东西非常简单:当用户单击LogInView()上的登录按钮时,我希望该应用隐藏LogInView()并显示{{1} },全屏显示,,就像模式,并且不允许用户返回。

这可以通过Swift和UIKit中的Storyboards轻松完成,有什么方法可以通过SwiftUI做到吗?

感谢您的帮助。 预先感谢。

我的代码:

LogInView

HomeView()

HomeView

struct LogInView: View {
    var body: some View {
        VStack {
            Text("Welcome to Mamoot!")
                .font(.largeTitle)
                .fontWeight(.heavy)
            Text("We are glad to have you here.")
            Text("Please log in with your Mastodon or Twitter account to continue.")
                .multilineTextAlignment(.center)
                .lineLimit(4)
                .padding()
            Spacer()
            FloatingTextField(title: "Username", placeholder: "Username", width: 300, type: "Username")
            FloatingTextField(title: "Password", placeholder: "Password", width: 300, type: "password")
                .padding(.top, -50)
            Spacer()
            ZStack {
                Button(action: { /* go to HomeView() */ }) {
                    Text("Log in")
                        .foregroundColor(Color.white)
                        .bold()
                        .shadow(color: .red, radius: 10)
                }
                .padding(.leading, 140)
                    .padding(.trailing, 140)
                    .padding(.top, 15)
                    .padding(.bottom, 15)
                    .background(Color.red)
                    .cornerRadius(10)
            }
            .padding(.bottom)
        }
    }
}

2 个答案:

答案 0 :(得分:5)

更新:我花了一些时间来更新答案并添加过渡。请注意,我更改了“按VStack分组”,否则过渡无效。

您可以更改withAnimation通话中的持续时间(按钮关闭)。

我还在按钮中移动了一些修饰符,因此整个过程都是“可插拔的”。否则,仅点击按钮上的文字将触发操作。


您可以使用ObservedObjectEnvironmentObjectBinding。这是ObservedObject的示例:

import SwiftUI

class Model: ObservableObject {
    @Published var loggedIn = false
}

struct ContentView: View {
    @ObservedObject var model = Model()

    var body: some View {
        VStack {
            if model.loggedIn {
                HomeView().transition(.opacity)
            } else {
                LogInView(model: model).transition(.opacity)
            }
        }
    }
}

struct HomeView: View {
    var body: some View {
        Text("Home Page")
    }
}

struct LogInView: View {
    @ObservedObject var model: Model

    var body: some View {
        VStack {
            Text("Welcome to Mamoot!")
                .font(.largeTitle)
                .fontWeight(.heavy)
            Text("We are glad to have you here.")
            Text("Please log in with your Mastodon or Twitter account to continue.")
                .multilineTextAlignment(.center)
                .lineLimit(4)
                .padding()
            Spacer()
            //            FloatingTextField(title: "Username", placeholder: "Username", width: 300, type: "Username")
            //            FloatingTextField(title: "Password", placeholder: "Password", width: 300, type: "password")
            //                .padding(.top, -50)
            Spacer()
            ZStack {
                Button(action: {
                    withAnimation(.easeInOut(duration: 1.0)) {
                        self.model.loggedIn = true
                    }
                }) {
                    Text("Log in")
                        .foregroundColor(Color.white)
                        .bold()
                        .shadow(color: .red, radius: 10)
                        // moved modifiers here, so the whole button is tappable
                        .padding(.leading, 140)
                        .padding(.trailing, 140)
                        .padding(.top, 15)
                        .padding(.bottom, 15)
                        .background(Color.red)
                        .cornerRadius(10)
                }
            }
            .padding(.bottom)
        }
    }
}

答案 1 :(得分:1)

@kontiki的回答可能是最SwiftUI-y,但是我将提出一个不同的解决方案,可能不那么好!但也许更灵活/可扩展。

您可以交换rootView of UIHostingController

SceneDelegate

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?
    fileprivate lazy var appCoordinator: AppCoordinator = {

        let rootViewController: UIHostingController<AnyView> = .init(rootView: EmptyView().eraseToAny())

        window?.rootViewController = rootViewController

        let navigationHandler: (AnyScreen, TransitionAnimation) -> Void = { [unowned rootViewController, window] (newRootScreen: AnyScreen, transitionAnimation: TransitionAnimation) in

            UIView.transition(
                with: window!,
                duration: 0.5,
                options: transitionAnimation.asUIKitTransitionAnimation,
                animations: { rootViewController.rootView = newRootScreen },
                completion: nil
            )
        }


        return AppCoordinator(
            dependencies: (
                securePersistence: KeyValueStore(KeychainSwift()),
                preferences: .default
            ),
            navigator: navigationHandler
        )
    }()

    func scene(
        _ scene: UIScene,
        willConnectTo session: UISceneSession,
        options connectionOptions: UIScene.ConnectionOptions
    ) {
        self.window = .fromScene(scene)
        appCoordinator.start()
    }
}

enum TransitionAnimation {
    case flipFromLeft
    case flipFromRight
}

private extension TransitionAnimation {
    var asUIKitTransitionAnimation: UIView.AnimationOptions {
        switch self {
        case .flipFromLeft: return UIView.AnimationOptions.transitionFlipFromLeft
        case .flipFromRight: return UIView.AnimationOptions.transitionFlipFromRight
        }
    }
}

AppCoordinator

这是AppCoordinator

    final class AppCoordinator {

    private let preferences: Preferences
    private let securePersistence: SecurePersistence
    private let navigationHandler: (AnyScreen, TransitionAnimation) -> Void

    init(

        dependencies: (securePersistence: SecurePersistence, preferences: Preferences),

        navigator navigationHandler: @escaping (AnyScreen, TransitionAnimation) -> Void

    ) {

        self.preferences = dependencies.preferences
        self.securePersistence = dependencies.securePersistence
        self.navigationHandler = navigationHandler
    }
}

// MARK: Internal
internal extension AppCoordinator {

    func start() {
        navigate(to: initialDestination)
    }
}

// MARK: Destination
private extension AppCoordinator {
    enum Destination {
        case welcome, getStarted, main
    }

    func navigate(to destination: Destination, transitionAnimation: TransitionAnimation = .flipFromLeft) {

        let screen = screenForDestination(destination)
        navigationHandler(screen, transitionAnimation)
    }

    func screenForDestination(_ destination: Destination) -> AnyScreen {
        switch destination {
        case .welcome: return AnyScreen(welcome)
        case .getStarted: return AnyScreen(getStarted)
        case .main: return AnyScreen(main)
        }
    }

    var initialDestination: Destination {
        guard preferences.hasAgreedToTermsAndPolicy else {
            return .welcome
        }

        guard securePersistence.isAccountSetup else {
            return .getStarted
        }

        return .main
    }

}

// MARK: - Screens
private extension AppCoordinator {

    var welcome: some Screen {
        WelcomeScreen()
            .environmentObject(
                WelcomeViewModel(
                    preferences: preferences,
                    termsHaveBeenAccepted: { [unowned self] in self.start() }
                )
            )
    }

    var getStarted: some Screen {
        GetStartedScreen()
            .environmentObject(
                GetStartedViewModel(
                    preferences: preferences,
                    securePersistence: securePersistence,
                    walletCreated: { [unowned self] in self.navigate(to: .main) }
                )
        )
    }

    var main: some Screen {
        return MainScreen().environmentObject(
            MainViewModel(
                preferences: preferences,
                securePersistence: securePersistence,
                walletDeleted: { [unowned self] in
                    self.navigate(to: .getStarted, transitionAnimation: .flipFromRight)
                }
            )
        )
    }
}