问题描述
尝试在macOS(本机而非Catalyst)上引用@Environment
对象horizontalSizeClass
和verticalSizeClass
的对象会导致以下错误:
'horizontalSizeClass'在macOS中不可用
'verticalSizeClass'在macOS中不可用
我很欣赏这些属性并不是真的适用于macOS,但这为创建通用的SwiftUI视图(即跨macOS,iOS等的跨平台)提供了很大的障碍。
一种解决方法是将所有特定于大小类的代码包装在条件编译中,但是结果是很多重复和冗余(请参见下面的示例)。
没有更有效的方法来处理此问题吗?
通用视图示例:
struct ExampleView: View {
#if !os(macOS)
@Environment(\.horizontalSizeClass) var horizontalSizeClass
#endif
private var item1: some View {
Text("Example Item 1")
}
private var item2: some View {
Text("Example Item 2")
}
private var item3: some View {
Text("Example Item 3")
}
var body: some View {
vstack {
#if !os(macOS)
if horizontalSizeClass == .compact {
vstack {
item1
item2
item3
}
} else {
HStack {
item1
item2
item3
}
}
#else
HStack {
item1
item2
item3
}
#endif
}
}
}
解决方法
诚然,macOS本身并不支持horizontalSizeClass
和verticalSizeClass
,但是好消息是添加它们很容易。
您可以通过创建符合@Environment
的{{1}},然后使用其扩展struct
来定义自己的EnvironmentKey
对象。
在macOS上实现大小类所需要做的全部工作如下。他们始终会返回EnvironmentValues
,但足以与iOS上的功能完全相同。
.regular
有了这个,您就不需要macOS的任何特殊功能。例如:
#if os(macOS)
enum UserInterfaceSizeClass {
case compact
case regular
}
struct HorizontalSizeClassEnvironmentKey: EnvironmentKey {
static let defaultValue: UserInterfaceSizeClass = .regular
}
struct VerticalSizeClassEnvironmentKey: EnvironmentKey {
static let defaultValue: UserInterfaceSizeClass = .regular
}
extension EnvironmentValues {
var horizontalSizeClass: UserInterfaceSizeClass {
get { return self[HorizontalSizeClassEnvironmentKey] }
set { self[HorizontalSizeClassEnvironmentKey] = newValue }
}
var verticalSizeClass: UserInterfaceSizeClass {
get { return self[VerticalSizeClassEnvironmentKey] }
set { self[VerticalSizeClassEnvironmentKey] = newValue }
}
}
#endif
只要将它们定义为struct ExampleView: View {
@Environment(\.horizontalSizeClass) var horizontalSizeClass
private var item1: some View {
Text("Example Item 1")
}
private var item2: some View {
Text("Example Item 2")
}
private var item3: some View {
Text("Example Item 3")
}
var body: some View {
VStack {
if horizontalSizeClass == .compact {
VStack {
item1
item2
item3
}
} else {
HStack {
item1
item2
item3
}
}
}
}
}
,您甚至可以将这些扩展放到更广泛使用的框架中。