迅速:提出主要和替代(登录/入职)流程时出现视觉故障? [英] Swift: visual glitches when presenting a Main and Alternative (login/onboarding) Flow?

查看:100
本文介绍了迅速:提出主要和替代(登录/入职)流程时出现视觉故障?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个应用程序,要求用户在首次启动该应用程序时登录或创建帐户. (尽管通常不建议这样做,但这是一个非常特定的用例.)

此外,如果它们已经登录,更新应用程序时,我想向他们显示一个屏幕,告诉他们新功能(如iOS12中的Notes,照片和音乐).

我遇到的问题是,在AppDelegate中更改"window"的"rootViewController"时,应用程序出现故障,并且在启用加载视图控制器之前,我可以瞬间看到主视图控制器.

有办法避免这种情况吗?可以将此逻辑封装在ViewControllers或AppDelegate中吗?

在不依赖多个实现的情况下,是否有一种可以用于这些场景中的一个或多个的单一机制?

解决方案

首先,当您处理多个流时,可以在这里有效使用情节提要.默认情况下,您的应用程序对主流程使用Main.storyboard.您的入职/替代流程可以包含在辅助情节提要中,例如. Onboarding.storyboard

这有很多优点:

  • 在一组开发人员中,每个用户流上的工作可以分开
  • 更清晰的源代码控制(git)
  • 关注点分离

启动应用程序时,您可以确定应显示哪个流程.逻辑可以包含在您的AppDelegate中:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    let isFirstRun = true // logic to determine goes here
    if isFirstRun {
        showOnboarding()
    }
    return true
}

为了显示入职"流程,值得考虑的是,一旦使用它的人完成了旅程,您将如何处理将其解雇的经验,这在语义上对您要创建的内容是正确的./p>

方法:

两种主要方法是:

  1. 交换应用程序主窗口的根视图控制器
  2. 将入职"流程作为一种模式旅程,与主要"流程重叠.

此实现应包含在AppDelegate的扩展中.

选项1:交换根视图控制器(良好)


切换根视图控制器是有好处的,尽管过渡选项仅限于UIViewAnimationOptions支持的过渡选项,所以根据您希望在流之间进行过渡的方式,可能意味着您必须实现自定义过渡-麻烦的.

您只需设置UIApplication.shared.keyWindow.rootViewController

即可显示入职流程 通过使用UIView.transition(with:)并将过渡样式作为UIViewAnimationOptions传递(在本例中为交叉溶解")来处理

解雇. (还支持翻转和卷发.)

在您第一次过渡到主视图时,还必须设置主视图的框架,然后再切换回主视图.

// MARK: - Onboarding

extension AppDelegate {

    func showOnboarding() {
        if let window = UIApplication.shared.keyWindow, let onboardingViewController = UIStoryboard(name: "Onboarding", bundle: nil).instantiateInitialViewController() as? OnboardingViewController {
            onboardingViewController.delegate = self
            window.rootViewController = onboardingViewController
        }
    }

    func hideOnboarding() {
        if let window = UIApplication.shared.keyWindow, let mainViewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() {
            mainViewController.view.frame = window.bounds
            UIView.transition(with: window, duration: 0.5, options: .transitionCrossDissolve, animations: {
                window.rootViewController = mainViewController
            }, completion: nil)
        }
    }
}

选项2:以模态方式(更好)呈现替代流


在最直接的实现方式中,由于用户在语义上是一次旅程,因此可以简单地在模式上下文中显示入职"流程.

Apple人机界面指南–方式:

仅在必须引起他人注意,必须完成或放弃一项任务才能继续使用该应用程序或保存重要数据时,才考虑创建模式上下文.

模态呈现允许在旅程结束时解雇的简单选择,而几乎没有交换控制器的麻烦.

自定义转换也受标准方式支持,因为它使用了ViewController.present() API:

// MARK: - Onboarding

extension AppDelegate {

    func showOnboarding() {
        if let window = window, let onboardingViewController = UIStoryboard(name: "Onboarding", bundle: nil).instantiateInitialViewController() as? OnboardingViewController {
            onboardingViewController.delegate = self
            window.makeKeyAndVisible()
            window.rootViewController?.present(onboardingViewController, animated: false, completion: nil)
        }
    }

    func hideOnboarding() {
        if let window = UIApplication.shared.keyWindow {
            window.rootViewController?.dismiss(animated: true, completion: nil)
        }
    }
}

I've got an App that requires the person to sign in or create an account the first time the App is launched. (Although this is not generally recommended, this is quite a specific use case.)

Furthermore, if they are already signed in, when the App is updated I'd like to show them a screen telling them about new features (as Notes, Photos and Music do in iOS12).

The problem I have is when changing the ‘rootViewController’ of ‘window’ in AppDelegate, the app glitches and I can see the main view controller for a split second, before the onboarding view controller becomes visible.

Is there a way to avoid this? Can this logic be encapsulated in ViewControllers or in the AppDelegate?

Is there a single mechanism that I can use for one or more of these scenarios that does not rely on multiple implementations?

解决方案

Firstly, as you are dealing with multiple flows, this is where Storyboards can be used effectively. By default your Application uses Main.storyboard for your primary flow. Your onboarding/alternative flow can be contained in a secondary storyboard, eg. Onboarding.storyboard

This has a number of advantages:

  • in a team of developers, the work on each user flow can be separated
  • clearer source control (git)
  • separation of concerns

When your App launches, you can determine which flow should be presented. The logic for this can be contained in your AppDelegate:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    let isFirstRun = true // logic to determine goes here
    if isFirstRun {
        showOnboarding()
    }
    return true
}

In order to show the Onboarding flow, it's worth considering how you'd like to handle the experience of dismissing it once the person using it has completed the journey, and which is semantically correct for what you are trying to create.

Approaches:

The two main approaches are:

  1. Swap the root view controller of the App's main window
  2. Present the Onboarding flow as a modal journey, overlapping the Main flow.

The implementation of this should be contained in an extension to AppDelegate.

Option 1: Swap the Root View Controller (Good)


There are benefits to switching the root view controller, although the transition options are limited to those supported by UIViewAnimationOptions, so depending on how you wish to transition between flows might mean you have to implement a custom transition - which can be cumbersome.

You can show the Onboarding flow by simply setting the UIApplication.shared.keyWindow.rootViewController

Dismissal is handled by utilizing UIView.transition(with:) and passing the transition style as a UIViewAnimationOptions, in this case Cross Dissolve. (Flips and Curls are also supported).

You also have to set the frame of the Main view before you transition back to it, as you're instantiating it for the first time.

// MARK: - Onboarding

extension AppDelegate {

    func showOnboarding() {
        if let window = UIApplication.shared.keyWindow, let onboardingViewController = UIStoryboard(name: "Onboarding", bundle: nil).instantiateInitialViewController() as? OnboardingViewController {
            onboardingViewController.delegate = self
            window.rootViewController = onboardingViewController
        }
    }

    func hideOnboarding() {
        if let window = UIApplication.shared.keyWindow, let mainViewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() {
            mainViewController.view.frame = window.bounds
            UIView.transition(with: window, duration: 0.5, options: .transitionCrossDissolve, animations: {
                window.rootViewController = mainViewController
            }, completion: nil)
        }
    }
}

Option 2: Present Alternative Flow Modally (Better)


In the most straightforward implementation, the Onboarding flow can simply be presented in a modal context, since semantically the User is on a single journey.

Apple Human Interface Guidelines – Modality:

Consider creating a modal context only when it’s critical to get someone’s attention, when a task must be completed or abandoned to continue using the app, or to save important data.

Presenting modally allows the simple option of dismissal at the end of the journey, with little of the cruft of swapping controllers.

Custom transitions are also supported in the standard way, since this uses the ViewController.present() API:

// MARK: - Onboarding

extension AppDelegate {

    func showOnboarding() {
        if let window = window, let onboardingViewController = UIStoryboard(name: "Onboarding", bundle: nil).instantiateInitialViewController() as? OnboardingViewController {
            onboardingViewController.delegate = self
            window.makeKeyAndVisible()
            window.rootViewController?.present(onboardingViewController, animated: false, completion: nil)
        }
    }

    func hideOnboarding() {
        if let window = UIApplication.shared.keyWindow {
            window.rootViewController?.dismiss(animated: true, completion: nil)
        }
    }
}

这篇关于迅速:提出主要和替代(登录/入职)流程时出现视觉故障?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆