独立 App 适配深色模式(三):实现选择页面与全局管理

关于我:大厂摸鱼 + 业余独立开发,之后会输出深度技术文章 + 独立开发技巧

我的往期技术文章合集:RickeyBoy - Gitbub

我的独立开发 App:iColors - 设计灵感 配色助手

iColors 的详细介绍:iColors色彩灵感App: 精选配色,图片取色,还有免费四季型人测试!

上一篇内容:独立 App 适配深色模式(二):颜色、图片的适配

⚙️ 第三步:深色模式选择页面

在 iColors 中,我为 App 内部的深浅模式选择设置了一个单独的页面,用户可以手动选择外观是浅色还是深色,亦或是跟随系统。具体的表现如下图所示:

当然,这一步并不是必须的。如果本着独立 App 一切从简的思路来说,不要这个设置页面也没问题,相当于是默认给用户一种选择------跟随系统。系统选择什么外观,App 内获取到,直接使用就行了。

不过我觉得增加一个设置页面更为方便和灵活,开发成本也不大,因此我最终还是做了这么一个页面。

具体要如何实现呢?首先我们需要定义一个枚举类型,代表集中不同的外观情况:

swift 复制代码
enum SchemeType: Int, Identifiable, CaseIterable {
    var id: Self { self }
    case light
    case dark
    case system
  
    /// 获取系统对应的 ColorScheme,用于设置
    var SystemColorScheme: ColorScheme? {
        switch self {
        case .light:
            return .light
        case .dark:
            return .dark
        case .system:
            // 返回 nil 代表不做单独处理
            return nil
        }
    }
}

我们需要通过 SystemColorScheme,来实现系统的外观类型,和我们自定义的枚举类型是可以一一对应上的。也就是说现在 SchemeType 是我们自定义的类型,而 ColorScheme 是系统的类型。

SchemeType.system 代表"跟随系统",而 ColorScheme == nil 代表没有对外观进行额外的设置,即不做处理。

有了 SchemeType 的类型,下一步我们就可以方便地写一个选择页面了:

swift 复制代码
body {
  ...
  ForEach(SchemeType.allCases) { item in
      SelectionView(...)
  }
}

🕹️ 第四步:全局管理

到现在基本上就是万事俱备只欠东风了,剩下需要做的就是增加全局的环境变量,用作统一管理。我们按照下面的方式定义一个 ObservableObject 即可:

swift 复制代码
final class ColorSchemeState : ObservableObject {
    @AppStorage("systemColorSchemeValue") private var currentSchemeValue: Int = SchemeType.system.rawValue
    
    /// App's Selected Color Scheme
    var currentScheme: SchemeType {
        get {
            return SchemeType(rawValue: currentSchemeValue) ?? .system
        }
        set {
            currentSchemeValue = newValue.rawValue
        }
    }
}

这里来稍微解释一下 ColorSchemeState:

  1. 首先我们通过 @AppStorage 声明了一个变量 currentSchemeValue 来记录外观颜色主题的选择,同时在 UserDefaults 中同步存储,可以记录用户的选择。
  2. currentScheme 是公开的计算属性,提供给外部来获取当前的外观主题
  3. 由于 ColorSchemeState 是一个 ObservableObject,当颜色方案改变时,相关的 UI 可以自动更新

接下来,我们只需要在 App 初始化时做两件事即可:

  1. 将 colorSchemeState 作为全局环境变量设置进去
  2. 通过 preferredColorScheme 设置默认外观颜色主题
swift 复制代码
@main
struct XXXApp: App {
  // ... 省略部分内容
  @StateObject var colorSchemeState = ColorSchemeState()
  
  WindowGroup {
    MainView()
    // ... 省略部分内容
      .preferredColorScheme(colorSchemeState.currentScheme.SystemColorScheme)
      .environmentObject(colorSchemeState)
  }
}

如果我们想要在某个具体的页面获取颜色主题信息,甚至于改变外观的选择,通过这样的方式就行了:

swift 复制代码
@EnvironmentObject var colorSchemeState: ColorSchemeState
colorSchemeState.currentScheme = ...

这样,我们整体的全局管理框架就已经搭建完成了!!


至此我们的深色模式适配就已经全部完结了,大家如果有问题欢迎提问和交流!

相关推荐
wfh1322 天前
国际 Android WPS Office v18.13 解锁版
app
小溪彼岸2 天前
【iOS小组件】小组件尺寸及类型适配
swiftui·swift
文件夹__iOS7 天前
[SwiftUI 开发] @dynamicCallable 与 callAsFunction:将类型实例作为函数调用
ios·swiftui·swift
小溪彼岸7 天前
【iOS小组件】iOS17与低版本兼容适配
swiftui·swift
Mamong8 天前
SwiftUI疑难杂症(1):sheet content多次执行
ios·swiftui·swift
AUV110712 天前
Mac剪贴板历史全记录!
macos·swiftui·mac·效率工具·实用工具·剪贴板·clipboard
AUV110712 天前
Mac 上哪个剪切板增强工具比较好用? 好用剪切板工具推荐
macos·swiftui·mac·剪贴板·clipboard·剪贴板增强·app 推荐
YesPMP平台官方12 天前
动动手指探索世界,旅游APP如何定制开发?
大数据·小程序·数据分析·app·旅游·软件开发
多彩电脑14 天前
SwiftUI里的ForEach使用的注意事项
macos·ios·swiftui·swift
guanpinkeji15 天前
加油卡APP定制搭建,让加油更便捷!
app·团队开发·软件开发·app开发·加油卡·加油卡app