iOS Swift 带有引导屏幕的应用程序的正确导航结构是什么?
What's the right navigation structure for iOS Swift app with onboarding screens?
我正在创建一个按如下方式运行的应用程序
- 启动屏幕
- 一个。如果已查看并接受 "Getting Started" 个屏幕,则打开主应用程序
- b。如果不是 viewed/accepted 则显示 "Getting started",然后在接受后显示主应用程序
"Getting Started" 屏幕非常独立,因此我为它们创建了一个故事板,而主应用程序将以编程方式创建。
(2) 的逻辑应该放在哪里?我正在考虑创建某种 UINavigationController,它位于两组屏幕之上,可以决定显示什么。或者,我打算只启动主应用程序 VC 并让逻辑将 "Getting Started" 显示为模态在那里。
请问有什么最佳实践建议吗?
在 AppDelegate 中使用代码启动。h/SceneDelegate.h
仅供参考,我相信你仍然可以混合故事板 ViewController 和代码 ViewController.However 我建议只坚持一种风格(在这种情况下,代码 ViewController 以编程方式)
然后使用UserDefault来存储用户是否点击"get started"
// Set Root VC
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(frame: UIScreen.main.bounds)
window?.windowScene = windowScene
let navigator = Container.shared.resolve(INavigator.self)!
let localStorageService = Container.shared.resolve(ILocalStorageService.self)!
if localStorageService.isKeyExist(key: Configs.KEY_USER) {
navigator.switchRoot(keyWindow: window!, scene: .main(viewModel: MainTabBarViewModel()))
} else {
navigator.switchRoot(keyWindow: window!, scene: .intro(viewModel: IntroViewModel()))
}
没有确定的答案。但是,您可以尝试稍微预测一下您的需求:
- 如果引导屏幕是您唯一会以这种方式显示的内容,那么您可以在
AppDelegate
或主视图控制器中添加一些代码,
- 如果您打算在某些版本后显示这种屏幕(例如展示新功能),您可以使用某种模式机制来显示可以关闭的全屏模式。
无论您选择哪种解决方案:
尝试将您的代码保持在适当的 class 或结构中:决定显示哪个屏幕以及如何创建视图控制器的逻辑必须在适当的 class 或结构中。此逻辑既不属于 AppDelegate
也不属于您的主视图控制器 — 顺便说一句,这就是您以庞大而混乱的视图控制器结束的方式。
根据您的需要(在多个同类实体之间进行选择),您可以查看 factory design pattern。它是一种封装逻辑以创建实体的通用结构。您可以将其设计为在您的控制器之间进行选择:
class RootViewControllerFactory {
var rootViewController: UIViewController {
if shouldDisplayOnboardingScreen() {
return generateOnboardingScreen()
} else {
return generateHomeScreen()
}
}
private func shouldDisplayOnboardingScreen() -> Bool {
// Your logic to decide whether you should display it or not.
}
func generateOnboardingScreen() -> UIViewController {
// Load it from your storyboard
}
func generateHomeScreen() -> UIViewController {
// Load it programmatically
}
}
然后,您的 AppDelegate
可以使用正确的视图控制器,但代码不会混淆在加载代码中。这使阅读更容易:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = RootViewControllerFactory().rootViewController
self.window?.makeKeyAndVisible()
return true
}
使用此解决方案,当 onboarding view controller 被关闭时,您可以调用工厂的 generateHomeScreen()
函数来获取主屏幕并切换到主屏幕。
我正在创建一个按如下方式运行的应用程序
- 启动屏幕
- 一个。如果已查看并接受 "Getting Started" 个屏幕,则打开主应用程序
- b。如果不是 viewed/accepted 则显示 "Getting started",然后在接受后显示主应用程序
"Getting Started" 屏幕非常独立,因此我为它们创建了一个故事板,而主应用程序将以编程方式创建。
(2) 的逻辑应该放在哪里?我正在考虑创建某种 UINavigationController,它位于两组屏幕之上,可以决定显示什么。或者,我打算只启动主应用程序 VC 并让逻辑将 "Getting Started" 显示为模态在那里。
请问有什么最佳实践建议吗?
在 AppDelegate 中使用代码启动。h/SceneDelegate.h 仅供参考,我相信你仍然可以混合故事板 ViewController 和代码 ViewController.However 我建议只坚持一种风格(在这种情况下,代码 ViewController 以编程方式)
然后使用UserDefault来存储用户是否点击"get started"
// Set Root VC
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(frame: UIScreen.main.bounds)
window?.windowScene = windowScene
let navigator = Container.shared.resolve(INavigator.self)!
let localStorageService = Container.shared.resolve(ILocalStorageService.self)!
if localStorageService.isKeyExist(key: Configs.KEY_USER) {
navigator.switchRoot(keyWindow: window!, scene: .main(viewModel: MainTabBarViewModel()))
} else {
navigator.switchRoot(keyWindow: window!, scene: .intro(viewModel: IntroViewModel()))
}
没有确定的答案。但是,您可以尝试稍微预测一下您的需求:
- 如果引导屏幕是您唯一会以这种方式显示的内容,那么您可以在
AppDelegate
或主视图控制器中添加一些代码, - 如果您打算在某些版本后显示这种屏幕(例如展示新功能),您可以使用某种模式机制来显示可以关闭的全屏模式。
无论您选择哪种解决方案:
尝试将您的代码保持在适当的 class 或结构中:决定显示哪个屏幕以及如何创建视图控制器的逻辑必须在适当的 class 或结构中。此逻辑既不属于 AppDelegate
也不属于您的主视图控制器 — 顺便说一句,这就是您以庞大而混乱的视图控制器结束的方式。
根据您的需要(在多个同类实体之间进行选择),您可以查看 factory design pattern。它是一种封装逻辑以创建实体的通用结构。您可以将其设计为在您的控制器之间进行选择:
class RootViewControllerFactory {
var rootViewController: UIViewController {
if shouldDisplayOnboardingScreen() {
return generateOnboardingScreen()
} else {
return generateHomeScreen()
}
}
private func shouldDisplayOnboardingScreen() -> Bool {
// Your logic to decide whether you should display it or not.
}
func generateOnboardingScreen() -> UIViewController {
// Load it from your storyboard
}
func generateHomeScreen() -> UIViewController {
// Load it programmatically
}
}
然后,您的 AppDelegate
可以使用正确的视图控制器,但代码不会混淆在加载代码中。这使阅读更容易:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = RootViewControllerFactory().rootViewController
self.window?.makeKeyAndVisible()
return true
}
使用此解决方案,当 onboarding view controller 被关闭时,您可以调用工厂的 generateHomeScreen()
函数来获取主屏幕并切换到主屏幕。