SwiftUI:用于通用(macOS 和 iOS)视图的 UserInterfaceSizeClass

SwiftUI: UserInterfaceSizeClass for Universal (macOS & iOS) Views

尝试在 macOS(本机,而非 Catalyst)上引用 @Environment 对象 horizontalSizeClassverticalSizeClass 会导致以下错误:

'horizontalSizeClass' is unavailable in macOS

'verticalSizeClass' is unavailable in macOS

我明白这些属性并不真正适用于 macOS,但这对创建通用的 SwiftUI 视图(即跨 macOS 的跨平台,iOS 等)构成了很大障碍。

一种解决方法是将所有大小为 class 的特定代码包装在条件编译中,但结果是大量重复和冗余(参见下面的示例)。

有没有更有效的方法来处理这个问题?

通用视图示例:

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 本身不支持 horizontalSizeClassverticalSizeClass,但好消息是添加它们很容易。

您可以定义自己的 @Environment 对象,方法是创建一个符合 EnvironmentKeystruct,然后使用它来扩展 EnvironmentValues

在 macOS 上实现大小 类 所需的全部内容如下。它们始终只是 return .regular,但足以发挥与 iOS.

完全相同的功能
#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

有了这个,您不需要为 macOS 做任何特殊的事情。例如:

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
                }
            }
        }
    }
}

您甚至可以将这些扩展放入一个框架中以便更广泛地使用,只要您将它们定义为 public