Completely move to other view and don't allow to go back in SwiftUI

前端 未结 2 580
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-01-13 03:36

I\'m developing a simple iOS app with SwiftUI with two views: a LogInView() and a HomeView().

What I want is really simple: when the user c

2条回答
  •  小鲜肉
    小鲜肉 (楼主)
    2021-01-13 04:04

    The answer by @kontiki is probably the most SwiftUI-y, but I will present a different solution, probably not as good! But maybe more flexible/scalable.

    You can swap rootView of UIHostingController:

    SceneDelegate

    class SceneDelegate: UIResponder, UIWindowSceneDelegate {
        var window: UIWindow?
        fileprivate lazy var appCoordinator: AppCoordinator = {
    
            let rootViewController: UIHostingController = .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

    And here is the 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)
                    }
                )
            )
        }
    }
    

提交回复
热议问题