SwiftUI如何优雅的管理暗黑or高亮模式?

前言

在2019年的全球开发者大会(WWDC)中,苹果推出了全球果粉最关心的iOS 13操作系统,内置崭新的「暗黑模式」。但是对于大多数开发者来说,在项目创建之后并没有精力来适配,通常手段为直接把暗黑模式关闭。

即:在 Info.plist 文件中,添加 key 为 User Interface Style,类型为 String,value 设置为 Light 即可。

存在即合理,虽然上述配置可以简单粗暴的关闭暗盒模式。但对于夜猫子们来说,并不能带来很友好的体验。So,本文将手把手教学如何管理暗黑模式~

准备思路

实现原理

首先在已经适配的APP当中,会存在跟随系统高亮模式暗黑模式切换的功能。所以,我们首先需要创建一个记录用户上一次选择的状态。对于首次安装的新用户,我们仅需要默认为跟随系统即可。

这里我们使用了 UserDefaults,是用户默认数据库的接口,一般用于存储用户信息、App 设置等基础信息。在用户切换的时候保存,并且更新全局暗黑or明亮模式的状态。

最后,我们需要在用户选择跟随系统时,获取系统当前的状态。

实现代码

获取启动后APP状态的源码
swift 复制代码
import SwiftUI

@main
struct MyDarkModelApp: App {
        
    @StateObject private var appearanceManager = AppearanceManager()
    
    @Environment(\.colorScheme) var colorScheme

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(appearanceManager)
                .preferredColorScheme(appearanceManager.isDarkMode ? .dark : .light)
        }
    }
}

class AppearanceManager: ObservableObject {
    
    enum AppearanceColor: Int {
        case iSystem = 0
        case iHight = 1
        case iDark = 2
    }
    
    @Published var isDarkMode: Bool = false
    
    @Published var type: AppearanceColor {
        didSet{
            switch type {
            case .iSystem:
                isDarkMode = (getCurrentInterfaceStyle() == .dark)
            case .iHight:
                isDarkMode = false
            case .iDark:
                isDarkMode = true
            }
            UserDefaults.standard.set(type.rawValue, forKey: "darkMode")
        }
    }
    
    init() {
        
        type = AppearanceColor(rawValue: UserDefaults.standard.integer(forKey: "darkMode")) ?? .iSystem
        switch type {
        case .iSystem:
            isDarkMode = (getCurrentInterfaceStyle() == .dark)
        case .iHight:
            isDarkMode = false
        case .iDark:
            isDarkMode = true
        }
                
    }
    
    func getCurrentInterfaceStyle() -> UIUserInterfaceStyle {
        if #available(iOS 13.0, *) {
            return UIScreen.main.traitCollection.userInterfaceStyle
        } else {
            // 在iOS 12或更早的版本中,默认为明亮模式
            return .light
        }
    }
    
}
用户切换APP状态并更新的源码
scss 复制代码
import SwiftUI

struct ContentView: View {
        
    @EnvironmentObject var appearanceManager: AppearanceManager
    
    var body: some View {
        VStack() {
            List {
                
                switch appearanceManager.type {
                case .iSystem:
                    Text("跟随系统")
                case .iHight:
                    Text("浅色模式")
                case .iDark:
                    Text("暗黑模式")
                }
                
                Text("点我设置明亮模式").foregroundColor(Color("TextColor")).onTapGesture {
                    appearanceManager.type = .iHight
                }
                
                Text("点我设置暗黑模式").foregroundColor(Color("TextColor")).onTapGesture {
                    appearanceManager.type = .iDark
                }
                
                Text("点我设置跟随系统").foregroundColor(Color("TextColor")).onTapGesture {
                    appearanceManager.type = .iSystem
                }
                
                Image("darkImage")
                
            }
        }.onAppear {
            print("isDarkMode----->\(appearanceManager.isDarkMode)")
        }
    }
}

相关拓展

颜色值、以及图片设置

方式1: 使用 Assets.xcassets 适配深色模式 (图片同理)

项目选择->Assets.xcassets->右键->New Color Set->设置名称,如图所示:

方式2: 使用 extension 适配深色模式 (图片同理)

swift 复制代码
extension UIColor {
  convenience init(light: UIColor, dark: UIColor) {
    self.init { traitCollection in
      switch traitCollection.userInterfaceStyle {
      case .light, .unspecified:
        return light
      case .dark:
        return dark
      @unknown default:
        return light
      }
    }
  }
}

extension Color {
  // 再定义一个颜色
  static let defaultBackground = Color(light: .white, dark: .black)
 
  init(light: Color, dark: Color) {
    self.init(UIColor(light: UIColor(light), dark: UIColor(dark)))
  }
}

最终效果

github地址

相关推荐
T1an-12 小时前
最右IOS岗一面
ios
坏小虎5 小时前
Expo 快速创建 Android/iOS 应用开发指南
android·ios·rn·expo
光影少年6 小时前
Android和iOS原生开发的基础知识对RN开发的重要性,RN打包发布时原生端需要做哪些配置?
android·前端·react native·react.js·ios
北京自在科技6 小时前
Find My 修复定位 BUG,AirTag 安全再升级
ios·findmy·airtag
Digitally7 小时前
如何不用 USB 线将 iPhone 照片传到电脑?
ios·电脑·iphone
Sim148019 小时前
iPhone将内置本地大模型,手机端AI实现0 token成本时代来临?
人工智能·ios·智能手机·iphone
Digitally21 小时前
如何将 iPad 上的照片传输到 U 盘(4 种解决方案)
ios·ipad
报错小能手1 天前
ios开发方向——swift并发进阶核心 @MainActor 与 DispatchQueue.main 解析
开发语言·ios·swift
LcGero1 天前
Cocos Creator 业务与原生通信详解
android·ios·cocos creator·游戏开发·jsb
ii_best1 天前
lua语言开发脚本基础、mql命令库开发、安卓/ios基础开发教程,按键精灵新手工具
android·ios·自动化·编辑器