如何在 SwiftUI 中提供“系统”外观选择?

Posted

技术标签:

【中文标题】如何在 SwiftUI 中提供“系统”外观选择?【英文标题】:How to provide a ‘System’ appearance choice in SwiftUI? 【发布时间】:2020-10-31 07:55:50 【问题描述】:

主要问题

抱歉,标题太长了。我正在尝试弄清楚如何为用户提供将应用程序的 ColorScheme 设置为“系统”的选择。

同样,让应用程序默认为系统的暗模式/亮模式。我知道 UIKit 有办法将样式设置为 .unspecified 但我不确定如何在 SwiftUI 中访问它。

我已经尝试将 .preferredColor() 设置为 nil,它有点工作,但有时它没有。我是 Swift 管理状态的新手,所以我肯定做错了什么。

附带问题: 当我将.preferredColor() 设置为.dark 时,我的模态设置表没有更新?它始终保持系统颜色。我在 ...App.swift 文件中的 ContentView() 上触发了 .preferredColor()

更新

我也解决了我的附带问题,只需将.preferredColor() 添加到模态表即可。这并不理想,但确实有效。但是我仍然无法弄清楚如何在 SwiftUI 中设置 .system 首选项

【问题讨论】:

【参考方案1】:

我最终找到了解决这个问题的两种方法。第一个是jinjie 发现的,另一个是我发现的。两种解决方案都可以是viewed here - repo。由rizwankce创建。

解决方案

我最终做的是使用包Introspect 从我使用ViewModifier 的主视图中获取UIViewController

ViewModifier 中,我只使用了.introspectViewController,这给了我UIViewController,这样我就可以像这样设置UIViewController.overrideUserInterfaceStyle = .unspecified。然后我只是根据下面没有看到的Picker 有条件地执行此操作。 ⤵


/// All themes
enum Themes: String 
    case Dark
    case Light
    case System


// MARK: - Theme Switch

struct ThemeSwitch: ViewModifier 
    let appStorage: String

    func body(content: Content) -> some View 
        content
            .introspectViewController  UIViewController in
                switch appStorage 
                case Themes.System.rawValue: UIViewController.overrideUserInterfaceStyle = .unspecified
                case Themes.Dark.rawValue: UIViewController.overrideUserInterfaceStyle = .dark
                case Themes.Light.rawValue: UIViewController.overrideUserInterfaceStyle = .light
                default: UIViewController.overrideUserInterfaceStyle = .unspecified
                
            
    


// MARK: - Extensions

extension View 
    func themeSwitch(appStorage: String) -> some View 
        modifier(ThemeSwitch(appStorage: appStorage))
    


我只是将所需主题作为字符串存储到 @State 对象中,该对象还更新了 @AppStorage 对象,因此无论如何应用程序始终可以选择。

您不必使用 Introspect,而是可以创建自己的包装器,但我已经安装了这个包,所以我想为什么不这样做。

替代解决方案

另一种解决方案是制作视图修改器并有条件地显示修改后的视图。条件基于ColorScheme 类型的可选数组、字典等。如果它不是 nil,它要么解开可选项,要么只显示未修改的视图。你可以在 repo 中找到它。上面提到的已关闭问题或拉取请求。

希望将来 Apple 会提供一种本地方式来实现这一点,但现在可以做到!如果出现更好的情况,我会尝试在将来更新此答案。

【讨论】:

以上是关于如何在 SwiftUI 中提供“系统”外观选择?的主要内容,如果未能解决你的问题,请参考以下文章

iOS14中点击SwiftUI列表项导航跳转返回后外观呈灰色的解决

SwiftUI List 在 Sheet 中的外观和行为与在 NavigationLink 中不同

如何在 SwiftUI WidgetKit 占位符中自定义占位符外观?

SwiftUI 4.0 实现朴素(Plain)的 Form 样式

SwiftUI 4.0 实现朴素(Plain)的 Form 样式

调整窗口大小时,SwiftUI TextField 文本边界无法使用 GeometryReader 更新,导致外观错误