SwiftUI 中的 Conditional Scene

在 SwiftUI 中,有时需要对新的 API 做隔离来保证兼容老的系统。

在 View 中很好解决,但是在 Scene 中,你可能会看到这样的错误提示。

Closure containing control flow statement cannot be used with result builder ‘SceneBuilder’

2023.2.17更新

在 Xcode 13.4 beta 中,SceneBuilder 支持了 buildExpressionbuildLimitedAvailabilitybuildOptional

解决思路

解决方法就是把需要用条件判断给出不同的 Scene 的部分单独写成一个函数,

返回 some Scene,同时不要使用 @SceneBuilder

body 中默认使用 @SceneBuilder 来支持多个 Scene

在 if-condition 中返回的可能是两个不同类型的 Scene,但是函数的返回值是
不透明的 some Scene,因此只要返回的内容是符合 Scene 协议的就可以。

可以参考我在 stackoverflow 上的回答

最后,上代码!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@main
struct YourApp: App {
var body: some Scene {
#if os(macOS)
// macOS
conditionalWindowScene().windowStyle(.hiddenTitleBar)
#else
// Other Platform
WindowGroup {
ContentView()
}
#endif
}

#if os(macOS)
/// Extract your conditional scene to avoid using `@SceneBuilder`
/// In `body`, SwiftUI will always use `@SceneBuilder` to build multiple Scene.
/// Because the result type is `some Scene`,
/// you just need to return a type that conforms to `Scene` Protocol.
func conditionalWindowScene() -> some Scene {
if #available(macOS 13.0, *) {
/// `Window` Scene is only available on macOS 13.0+
return Window("App", id: "MAIN") {
ContentView()
}
} else {
/// Otherwise, using `WindowGroup`
return WindowGroup {
ContentView()
}
}
}
#endif
}
作者

LiYanan

发布于

2023-01-01

更新于

2023-02-18

许可协议

评论