使用 SwiftUI 在不同的 UI 层次结构之间切换的正确方法是啥?
Posted
技术标签:
【中文标题】使用 SwiftUI 在不同的 UI 层次结构之间切换的正确方法是啥?【英文标题】:What is the correct way to switch between distinct UI hierarchies with SwiftUI?使用 SwiftUI 在不同的 UI 层次结构之间切换的正确方法是什么? 【发布时间】:2019-09-04 00:13:20 【问题描述】:想象一个典型的应用程序,它具有引导、登录/注册和某种内容。当应用程序加载时,您需要决定要显示哪个视图。一个简单的实现可能如下所示:
struct ContentView: View
//assuming some centralized state that keeps track of basic user activity
@State var applicationState = getApplicationState()
var body: some View
if !applicationState.hasSeenOnboarding
return OnBoarding()
if !applicationState.isSignedIn
return Registration()
return MainContent()
显然这种方法失败了,因为 SwiftUI 视图需要不透明的返回类型 some View
。这可以使用AnyView
包装器类型来缓解(尽管有点骇人听闻),它提供类型擦除并允许编译下面的代码。
struct ContentView: View
//assuming some centralized state that keeps track of basic user activity
@State var applicationState = getApplicationState()
var body: some View
if !applicationState.hasSeenOnboarding
return AnyView(OnBoarding())
if !applicationState.isSignedIn
return AnyView(Registration())
return AnyView(MainContent())
有没有更正确的方法不需要使用AnyView
? SceneDelegate
中是否有可以处理转换到完全不同的视图层次结构的功能?
【问题讨论】:
您可以使用 ZStack 代替 AnyView。 这在技术上确实有效。有没有更好的方法来处理这种情况?else if
我不是两个单独的if
语句?诚实地?很难说 - 但很好的问题和赞成。事情是这样的——Swift
开发最佳实践花了多长时间? (有吗?)人们可能会称这是一个糟糕的问题,因为它征求意见。让我给你两个。 (1)UIKit
是如何处理的?在RxSwift
?我这里没有好的答案。 (2) 也许将尽可能多的逻辑移入模型或ObservedObject
,实际上返回 any View
?我想这取决于你对于仍然相当脆弱的测试平台的“有没有更好的方法”的意思。
感谢@dfd,我的直觉是,这可能是 SceneDelegate 可以处理的情况,但我在 src 中没有发现任何实际支持这种直觉的东西。猜猜我只是想弄清楚其他早期的 SwiftUI 探索者是否遇到过这个问题并更优雅地解决了这个问题。今晚晚些时候我将尝试使用 Group 方法!
@superpuccio 是很好的回答者之一。我使用这种技术Group
来保持图像选择器全屏显示或显示我的“正常” UI - 它运行良好。
【参考方案1】:
可能最SwiftUI
-y 执行此类操作的方法是使用Group
视图:
import SwiftUI
struct ContentView: View
@State private var applicationState = getApplicationState()
var body: some View
Group
if !applicationState.hasSeenOnboarding
OnBoarding()
else if !applicationState.isSignedIn
Registration()
else
MainContent()
struct ContentView_Previews: PreviewProvider
static var previews: some View
ContentView()
需要注意的最重要的事情是,这样一来,您就不会依赖 AnyView
的类型擦除(如果不是绝对必要的话,可以避免)。
如果您想将初始视图创建封装在一个方法中,请不要使用类型擦除。相反,请使用 some
关键字:
import SwiftUI
struct ContentView: View
@State private var applicationState = getApplicationState()
private func initialView() -> some View
if !applicationState.hasSeenOnboarding
OnBoarding()
else if !applicationState.isSignedIn
Registration()
else
MainContent()
var body: some View
initialView()
struct ContentView_Previews: PreviewProvider
static var previews: some View
ContentView()
【讨论】:
谢谢!这似乎是目前要走的路。以上是关于使用 SwiftUI 在不同的 UI 层次结构之间切换的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
Android Studio 4.0+ 中新的 UI 层次结构调试工具