ios - SwiftUI:用于通用(macOS 和 iOS) View 的 UserInterfaceSizeClass

标签 ios macos swiftui cross-platform size-classes

尝试在 macOS( native ,而非 Catalyst)上引用 @Environment 对象 horizo​​ntalSizeClassverticalSizeClass 会导致以下错误:

'horizontalSizeClass' is unavailable in macOS

'verticalSizeClass' is unavailable in macOS

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

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

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

通用 View 示例:

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

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

在 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

有了这个,您就不需要为 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

关于ios - SwiftUI:用于通用(macOS 和 iOS) View 的 UserInterfaceSizeClass,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63526478/

相关文章:

iphone - 在核心数据中保存一对多关系时出现问题

ios - 如何通过 .mp3 文件过滤 MPMediaItems 以在 AVPlayer 中播放歌曲

macos - 无法访问 redis docker 卷

list - SwiftUI - 使列表分隔线扩展到触摸屏边缘

ios - 偏移不会在onTapGesture之后重置-SwiftUI

ios - SwiftUI 如何在 UIBarButtonItem 上添加操作?

ios - 您如何确定 XCode 使用的构建选项,以便您可以将它们与 xcodebuild 一起使用?

objective-c - 使用 objective zip 解压 NSData

xcode - Mac 应用程序的设计 View

swift - NSWorkspace setDesktopImageURL 适合屏幕