Swift:暗黑模式iOS 13以上支持是否跟随系统和iOS13以下的主题适配

简介: Swift:暗黑模式iOS 13以上支持是否跟随系统和iOS13以下的主题适配

image.png


JKSwiftExtensionJKDarkModeUtilJKThemeProvider 有源码

  • 目录:
  • 1、暗黑模式介绍
  • 2、暗黑模式的关闭和打开
  • 3、iOS 13 暗黑模式的适配 (重点看)
  • 4、iOS 13 以下主题的适配:浅色和深色 (重点看)
  • 5、一次适配不完的问题


一、暗黑模式的介绍



  • 1.1、暗黑模式的简介
    从 iOS 13.0 版本开始,用户可以选择采用系统范围内的浅色或深色外观。 深色外观(称为暗黑模式DarkMode)实现了许多应用程序已经采用的界面样式。 用户可以选择自己喜欢的美学,也可以选择根据环境照明条件或特定时间表来切换其界面。


image.png

  • 所有应用程序都应该支持浅色和深色界面样式,但在某些地方的特定外观可能会表现更好。例如,您可能总是为印刷内容采用轻巧的外观。
    在更改代码之前,请打开黑暗模式,看看应用程序的反应。系统为您做了很多工作,如果您的应用程序使用标准视图和控件,您可能不需要进行许多更改。标准视图和控件会自动更新其外观,以匹配当前界面样式。如果您已经使用颜色和图像资产,您可以在不更改代码的情况下添加深色变体。
  • 1.2、UITraitCollection介绍
    在 iOS 13 中,我们可以通过 UITraitCollection 来判断当前系统的模式。UIView 和 UIViewController 、UIScreen、UIWindow 都已经遵从了UITraitEnvironment 这个协议,因此这些类都拥有一个叫做 traitCollection 的属性,在这些类中,我们可以这样去判断当前 App 的颜色模式:


let isDark = self.traitCollection.userInterfaceStyle == .dark
  • 1.3、模拟器暗黑模式切换的快捷键:command+shift+A


二、暗黑模式的关闭和打开



  • 2.1、自己的app还没有适配暗黑模式又担心用户使用暗黑模式的时候界面不好看:关闭暗黑模式


  • 方式一:暂时全局关闭暗黑模式:
    Info.plist 文件中,添加 key 为 User Interface Style,类型为 String,value 设置为 Light 即可


image.png

  • 方式二:使用代码的方式
    强制关闭暗黑模式
if(@available(iOS 13.0,*)){
   UIApplication.shared.windows.filter({$0.isKeyWindow}).first?.overrideUserInterfaceStyle = .light
}
  • 2.2、单个页面关闭暗黑模式
self.overrideUserInterfaceStyle = .light
  • 提示:设置此属性会影响当前 view/viewController/window 以及它下面的任何内容

如果你希望一个子视图监听系统的模式,请将 overrideUserInterfaceStyle 属性设置为unspecified

self.overrideUserInterfaceStyle = .unspecified


三、iOS 13 暗黑模式的适配



  • 3.1、iOS 13的暗黑模式我们主要分为:跟随系统模式自定义模式
  • 跟随系统,需要设置:


UIApplication.shared.windows.filter({$0.isKeyWindow}).first?.overrideUserInterfaceStyle = .unspecified
  • 不跟随系统
    浅色:UIApplication.shared.windows.filter({$0.isKeyWindow}).first?.overrideUserInterfaceStyle = .light
    深色:UIApplication.shared.windows.filter({$0.isKeyWindow}).first?.overrideUserInterfaceStyle = .dark
  • 3.2、iOS 13的暗黑模式适配代码在:JKDarkModeUtil 里面,默认是 跟随系统模式,主要代码如下


import UIKit
public class JKDarkModeUtil {
    /// 跟随系统的key
    private static let JKDarkToSystem = "JKDarkToSystem"
    /// 是否浅色模式的key
    private static let JKLightDark = "JKLightDark"
    /// 是否浅色
    public static var isLight: Bool {
        if let value = UserDefaults.jk.userDefaultsGetValue(key: JKLightDark) as? Bool {
            return value
        }
        return true
    }
    /// 是否跟随系统
    public static var isFloorSystem: Bool {
        if #available(iOS 13, *) {
            if let value = UserDefaults.jk.userDefaultsGetValue(key: JKDarkToSystem) as? Bool {
                return value
            }
            return true
        }
        return false
    }
}
// MARK:- 方法的调用
extension JKDarkModeUtil: JKThemeable {
    public func apply() {}
}
public extension JKDarkModeUtil {
    // MARK: 初始化的调用
    /// 默认设置
    static func defaultDark() {
        if #available(iOS 13.0, *) {
            // 默认跟随系统暗黑模式开启监听
            if (JKDarkModeUtil.isFloorSystem) {
                JKDarkModeUtil.setDarkModeFollowSystem(isFollowSystem: true)
            } else {
                UIApplication.shared.windows.filter({$0.isKeyWindow}).first?.overrideUserInterfaceStyle = JKDarkModeUtil.isLight ? .light : .dark
            }
        }
    }
    // MARK: 设置系统是否跟随
    static func setDarkModeFollowSystem(isFollowSystem: Bool) {
        if #available(iOS 13.0, *) {
            // 1.1、设置是否跟随系统
            UserDefaults.jk.userDefaultsSetValue(value: isFollowSystem, key: JKDarkToSystem)
            let result = UITraitCollection.current.userInterfaceStyle == .light ? true : false
            UserDefaults.jk.userDefaultsSetValue(value: result, key: JKLightDark)
            // 1.2、设置模式的保存
            if isFollowSystem {
                UIApplication.shared.windows.filter({$0.isKeyWindow}).first?.overrideUserInterfaceStyle = .unspecified
            } else {
                UIApplication.shared.windows.filter({$0.isKeyWindow}).first?.overrideUserInterfaceStyle = UITraitCollection.current.userInterfaceStyle
            }
        }
    }
    // MARK: 设置:浅色 / 深色
    static func setDarkModeCustom(isLight: Bool) {
        if #available(iOS 13.0, *) {
            // 1.1、只要设置了模式:就是黑或者白
            UIApplication.shared.windows.filter({$0.isKeyWindow}).first?.overrideUserInterfaceStyle = isLight ? .light : .dark
            // 1.2、设置跟随系统:否
            UserDefaults.jk.userDefaultsSetValue(value: false, key: JKDarkToSystem)
            UserDefaults.jk.userDefaultsSetValue(value: isLight, key: JKLightDark)
        } else {
            // 模式存储
            UserDefaults.jk.userDefaultsSetValue(value: isLight, key: JKLightDark)
            // 通知模式更新
            LegacyThemeProvider.shared.updateTheme()
        }
    }
}
// MARK:- 动态颜色的使用
public extension JKDarkModeUtil {
    static func colorLightDark(light: UIColor, dark: UIColor) -> UIColor {
        if #available(iOS 13.0, *) {
            return UIColor { (traitCollection) -> UIColor in
                if JKDarkModeUtil.isFloorSystem {
                    if traitCollection.userInterfaceStyle == .light {
                        return light
                    } else {
                        return dark
                    }
                } else {
                    return JKDarkModeUtil.isLight ? light : dark
                }
            }
        } else {
            // iOS 13 以下主题色的使用
            if JKDarkModeUtil.isLight {
                return light
            }
            return dark
        }
    }
}
// MARK:- 动态图片的使用
public extension JKDarkModeUtil {
    // MARK: 深色图片和浅色图片切换 (深色模式适配)
    /// 深色图片和浅色图片切换 (深色模式适配)
    /// - Parameters:
    ///   - light: 浅色图片
    ///   - dark: 深色图片
    /// - Returns: 最终图片
    static func image(light: UIImage?, dark: UIImage?) -> UIImage? {
        if #available(iOS 13.0, *) {
            guard let weakLight = light, let weakDark = dark, let config = weakLight.configuration else { return light }
            let lightImage = weakLight.withConfiguration(config.withTraitCollection(UITraitCollection.init(userInterfaceStyle: UIUserInterfaceStyle.light)))
            lightImage.imageAsset?.register(weakDark, with: config.withTraitCollection(UITraitCollection(userInterfaceStyle: UIUserInterfaceStyle.dark)))
            return lightImage.imageAsset?.image(with: UITraitCollection.current) ?? light
        } else {
            // iOS 13 以下主题色的使用
            if JKDarkModeUtil.isLight {
                return light
            }
            return dark
        }
    }
}
  • 3.3、UIColor 颜色的使用方式


JKDarkModeUtil.colorLightDark(light: UIColor.yellow, dark: UIColor.green)
  • 提示:建议自定义业务色,如下


// MARK:- 业务颜色的使用
extension UIColor {
    /// 背景色
    private(set) static var cA1 = JKDarkModeUtil.colorLightDark(light: UIColor.yellow, dark: UIColor.green)
}
  • 使用:self.view.backgroundColor = .cA1
  • 3.4、CGColor 适配,实现 traitCollectionDidChange 方法,适配颜色即可


override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)
    // cgColor 颜色适配
    button.layer.borderColor = JKDarkModeUtil.colorLightDark(light: .green, dark: .brown).cgColor
}


  • Assets中添加图片


image.png

  • 代码适配图片


// MARK:- 动态图片的使用(网络图片一样)
public extension JKDarkModeUtil {
    // MARK: 深色图片和浅色图片切换 (深色模式适配)
    /// 深色图片和浅色图片切换 (深色模式适配)
    /// - Parameters:
    ///   - light: 浅色图片
    ///   - dark: 深色图片
    /// - Returns: 最终图片
    static func image(light: UIImage?, dark: UIImage?) -> UIImage? {
         if #available(iOS 13.0, *) {
            guard let weakLight = light, let weakDark = dark, let config = weakLight.configuration else { return light }
            let lightImage = weakLight.withConfiguration(config.withTraitCollection(UITraitCollection.init(userInterfaceStyle: UIUserInterfaceStyle.light)))
            lightImage.imageAsset?.register(weakDark, with: config.withTraitCollection(UITraitCollection(userInterfaceStyle: UIUserInterfaceStyle.dark)))
            return lightImage.imageAsset?.image(with: UITraitCollection.current) ?? light
         } else {
            // iOS 13 以下主题色的使用
            if JKDarkModeUtil.isLight {
               return light
            }
            return dark
         }
   }
}


  • 提示:代码适配的时候需要在:traitCollectionDidChange 方法里面再次赋值,iOS 13 以上的建议直接再 Assets中添加图片
    如果是 cell 里面的图直接使用方法加载图片,刷新一下视图即可


四、iOS 13 以下主题的适配:浅色和深色



  • 4.1、iOS 13 以下我们采用的是监听模式来改变主题色,源码在 JKThemeProvider,使用步骤如下
  • 1>、遵守协议 JKThemeable (遵守UITraitEnvironment协议的均可使用)


extension ViewController: JKThemeable {
    func apply() {
       self.view.backgroundColor = JKDarkModeUtil.colorLightDark(light: UIColor.yellow, dark: UIColor.green)
    }
}
  • 2>、注册监听模式变化


themeProvider.register(observer: self)
  • 3>、模式变化通知


JKDarkModeUtil.setDarkModeCustom(isLight: true)
  • 4.2、颜色的调用和图片模式的调用和iOS13一样
  • 颜色调用


JKDarkModeUtil.colorLightDark(light: UIColor.yellow, dark: UIColor.green)
  • 图片调用


JKDarkModeUtil.image(light: UIImage(named: "tabbar_profile"), dark: UIImage(named: "tabbar_profile_selected"))
  • 4.3、主题变化后会走代理 apply(),在代理方法里面我们只需要重新调用颜色或者图片的方法即可


extension ViewController: JKThemeable {
    func apply() {
        self.view.backgroundColor = JKDarkModeUtil.colorLightDark(light: UIColor.yellow, dark: UIColor.green)
        darkImageView.image = JKDarkModeUtil.image(light: UIImage(named: "tabbar_profile"), dark: UIImage(named: "tabbar_profile_selected"))
    }
}


五、一次适配不完的问题



  • 5.1、一次适配不完的问题,我们在使用JKDarkModeUtil 调用一些方法的时候,适配哪里就哪里使用即可,不使用的就按照之前的颜色以及图片调用即可
  • 5.2、提示:在使用 JKDarkModeUtilJKThemeProvider 的时候,需要在设置 windowrootViewController 后需要调用 JKDarkModeUtil.defaultDark()
目录
相关文章
|
23天前
|
安全 Android开发 数据安全/隐私保护
深入探讨iOS与Android系统安全性对比分析
在移动操作系统领域,iOS和Android无疑是两大巨头。本文从技术角度出发,对这两个系统的架构、安全机制以及用户隐私保护等方面进行了详细的比较分析。通过深入探讨,我们旨在揭示两个系统在安全性方面的差异,并为用户提供一些实用的安全建议。
|
10天前
|
安全 Swift iOS开发
Swift 与 UIKit 在 iOS 应用界面开发中的关键技术和实践方法
本文深入探讨了 Swift 与 UIKit 在 iOS 应用界面开发中的关键技术和实践方法。Swift 以其简洁、高效和类型安全的特点,结合 UIKit 丰富的组件和功能,为开发者提供了强大的工具。文章从 Swift 的语法优势、类型安全、编程模型以及与 UIKit 的集成,到 UIKit 的主要组件和功能,再到构建界面的实践技巧和实际案例分析,全面介绍了如何利用这些技术创建高质量的用户界面。
20 2
|
19天前
|
安全 数据安全/隐私保护 Android开发
深入探索iOS系统安全机制:从基础到高级
本文旨在全面解析iOS操作系统的安全特性,从基础的权限管理到高级的加密技术,揭示苹果如何构建一个既开放又安全的移动平台。我们将通过实例和分析,探讨iOS系统如何保护用户数据免受恶意软件、网络攻击的威胁,并对比Android系统在安全性方面的差异。
|
25天前
|
安全 搜索推荐 Android开发
揭秘安卓与iOS系统的差异:技术深度对比
【10月更文挑战第27天】 本文深入探讨了安卓(Android)与iOS两大移动操作系统的技术特点和用户体验差异。通过对比两者的系统架构、应用生态、用户界面、安全性等方面,揭示了为何这两种系统能够在市场中各占一席之地,并为用户提供不同的选择。文章旨在为读者提供一个全面的视角,理解两种系统的优势与局限,从而更好地根据自己的需求做出选择。
68 2
|
26天前
|
Swift iOS开发 UED
如何使用Swift和UIKit在iOS应用中实现自定义按钮动画
本文通过一个具体案例,介绍如何使用Swift和UIKit在iOS应用中实现自定义按钮动画。当用户点击按钮时,按钮将从圆形变为椭圆形,颜色从蓝色渐变到绿色;释放按钮时,动画以相反方式恢复。通过UIView的动画方法和弹簧动画效果,实现平滑自然的过渡。
48 1
|
2月前
|
安全 搜索推荐 Android开发
深入探索安卓与iOS系统的差异及其对用户体验的影响
在当今的智能手机市场中,安卓和iOS是两大主流操作系统。它们各自拥有独特的特性和优势,为用户提供了不同的使用体验。本文将深入探讨安卓与iOS系统之间的主要差异,包括它们的设计理念、用户界面、应用生态以及安全性等方面,并分析这些差异如何影响用户的使用体验。
|
2月前
|
Swift iOS开发 UED
如何使用Swift和UIKit在iOS应用中实现自定义按钮动画
【10月更文挑战第18天】本文通过一个具体案例,介绍如何使用Swift和UIKit在iOS应用中实现自定义按钮动画。当用户按下按钮时,按钮将从圆形变为椭圆形并从蓝色渐变为绿色;释放按钮时,动画恢复原状。通过UIView的动画方法和弹簧动画效果,实现平滑自然的动画过渡。
50 5
|
2月前
|
安全 搜索推荐 Android开发
揭秘iOS与Android系统的差异:一场技术与哲学的较量
在当今数字化时代,智能手机操作系统的选择成为了用户个性化表达和技术偏好的重要标志。iOS和Android,作为市场上两大主流操作系统,它们之间的竞争不仅仅是技术的比拼,更是设计理念、用户体验和生态系统构建的全面较量。本文将深入探讨iOS与Android在系统架构、应用生态、用户界面及安全性等方面的本质区别,揭示这两种系统背后的哲学思想和市场策略,帮助读者更全面地理解两者的优劣,从而做出更适合自己的选择。
|
24天前
|
安全 Android开发 iOS开发
深入探索iOS与Android系统的差异性及优化策略
在当今数字化时代,移动操作系统的竞争尤为激烈,其中iOS和Android作为市场上的两大巨头,各自拥有庞大的用户基础和独特的技术特点。本文旨在通过对比分析iOS与Android的核心差异,探讨各自的优势与局限,并提出针对性的优化策略,以期为用户提供更优质的使用体验和为开发者提供有价值的参考。
|
26天前
|
安全 Android开发 iOS开发
安卓系统与iOS系统的比较####
【10月更文挑战第26天】 本文将深入探讨安卓(Android)和iOS这两大主流移动操作系统的各自特点、优势与不足。通过对比分析,帮助读者更好地理解两者在用户体验、应用生态、系统安全等方面的差异,从而为消费者在选择智能手机时提供参考依据。无论你是技术爱好者还是普通用户,这篇文章都将为你揭示两大系统背后的故事和技术细节。 ####
42 0