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

The*_*eil 4 macos cross-platform ios size-classes swiftui

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

“horizo​​ntalSizeClass”在 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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

The*_*eil 14

确实,macOS 本身不支持horizontalSizeClassverticalSizeClass,但好消息是添加它们很容易。

您可以通过创建符合 的a 来定义自己的@Environment对象,然后使用它来扩展。structEnvironmentKeyEnvironmentValues

在 macOS 上实现尺寸类别所需的全部内容如下。它们随时都会返回.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.self] }
        set { self[HorizontalSizeClassEnvironmentKey.self] = newValue }
    }
    var verticalSizeClass: UserInterfaceSizeClass {
        get { return self[VerticalSizeClassEnvironmentKey.self] }
        set { self[VerticalSizeClassEnvironmentKey.self] = newValue }
    }
}
#endif
Run Code Online (Sandbox Code Playgroud)

完成此操作后,您就不需要为 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
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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