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

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

问题描述

我有一个应用,要求用户在该应用首次启动时登录或创建帐户.(虽然通常不推荐这样做,但这是一个非常具体的用例.)

此外,如果他们已经登录,当应用更新时我想向他们展示一个屏幕,告诉他们新功能(如 iOS12 中的笔记、照片和音乐).

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

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

是否有一种机制可以用于一种或多种不依赖于多种实现的场景?

解决方案

首先,当您处理多个流程时,这是可以有效使用 Storyboard 的地方.默认情况下,您的应用程序使用 Main.storyboard 作为您的主要流程.您的入职/替代流程可以包含在辅助故事板中,例如.Onboarding.storyboard

这有很多优点:

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

当您的应用启动时,您可以确定应该呈现哪个流.这个逻辑可以包含在你的 AppDelegate 中:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) ->布尔{let isFirstRun = true//确定的逻辑在这里如果是第一次运行{showOnboarding()}返回真}

为了展示 Onboarding 流程,值得考虑您希望如何处理在使用它的人完成旅程后关闭它的体验,并且这在语义上对于您尝试创建的内容是正确的.

方法:

两种主要方法是:

  1. 交换应用主窗口的根视图控制器
  2. 将入职流程呈现为模态旅程,与主要流程重叠.

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

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

<小时>

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

您可以通过简单地设置 UIApplication.shared.keyWindow.rootViewController

来显示 Onboarding 流程

Dismissal 是通过利用 UIView.transition(with:) 并将过渡样式作为 UIViewAnimationOptions 传递来处理的,在本例中为 Cross Dissolve.(也支持翻转和卷曲).

在转换回主视图之前,您还必须设置主视图的框架,因为这是第一次实例化它.

//MARK: - 入职扩展 AppDelegate {func showOnboarding() {if let window = UIApplication.shared.keyWindow, let onboardingViewController = UIStoryboard(name: "Onboarding", bundle: nil).instantiateInitialViewController() as?OnboardingViewController {onboardingViewController.delegate = selfwindow.rootViewController = onboardingViewController}}func hideOnboarding() {if let window = UIApplication.shared.keyWindow, let mainViewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() {mainViewController.view.frame = window.boundsUIView.transition(with: window, duration: 0.5, options: .transitionCrossDissolve, animations: {window.rootViewController = mainViewController},完成:无)}}}

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

<小时>

在最直接的实现中,入职流程可以简单地在模态上下文中呈现,因为从语义上讲,用户处于单次旅程中.

<块引用>

Apple 人机界面指南 - 模态::>

仅当需要引起某人的注意、必须完成或放弃任务才能继续使用应用程序或保存重要数据时,才考虑创建模态上下文.

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

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

//MARK: - 入职扩展 AppDelegate {func showOnboarding() {如果让窗口 = 窗口,让 onboardingViewController = UIStoryboard(name: "Onboarding", bundle: nil).instantiateInitialViewController() as?OnboardingViewController {onboardingViewController.delegate = selfwindow.makeKeyAndVisible()window.rootViewController?.present(onboardingViewController, 动画: false, 完成: nil)}}func hideOnboarding() {如果让窗口 = UIApplication.shared.keyWindow {window.rootViewController?.dismiss(动画:true,完成: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)
        }
    }
}

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

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