news 2026/8/22 14:40:04

深色模式适配一次搞定:Colorful如何用traitCollectionDidChange优雅切换明暗主题

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深色模式适配一次搞定:Colorful如何用traitCollectionDidChange优雅切换明暗主题

深色模式适配一次搞定:Colorful如何用traitCollectionDidChange优雅切换明暗主题

【免费下载链接】Color-Picker-for-iOSColorful: iOS color picker built with Swift.项目地址: https://gitcode.com/gh_mirrors/co/Color-Picker-for-iOS

Colorful 是一款用 Swift 编写的 iOS 取色器(Color Picker)库,它在深色模式适配上做了一个非常值得学习的示范:借助系统的traitCollectionDidChange回调,配合动态颜色,一次搞定明暗主题切换,无需手动监听通知、也不会出现"切一次主题才生效一次"的尴尬。🌗

为什么深色模式适配总是做不干净?

很多 iOS 项目遇到深色模式时,最常见的翻车姿势有这几种:

  • 硬编码颜色UIColor(white: 0.89, alpha: 1)写死了浅色值,深色下变成一块刺眼的"白斑";
  • 手动监听通知:到处监听UIColorAppearance或自定义通知,注册时机稍晚就错过首次切换;
  • 切换后不刷新:Layer 上的颜色是"快照",CGColor不会随主题自动更新,切完主题界面还是旧样子。

Colorful 的做法是:能用系统动态颜色就用,必须刷新的 Layer 属性,交给每个视图自己的traitCollectionDidChange统一处理

Colorful 的深色模式适配思路:动态颜色打底

Colorful 的核心 UI 由四个部分组成,源码都在Colorful/Classes/目录下:

组件文件职责
色相/饱和度圆盘ColorMapView.swift绘制颜色映射图,外圈描边需随主题变化
明度滑条BrightnessSlider.swift滚轮式亮度选择,边框与阴影渐变随主题变化
明度游标BrightnessCursor.swift显示当前色值 HEX
圆盘游标ColorMapCursor.swift显示当前选中色

在边框这类装饰性颜色上,Colorful 优先使用 iOS 13+ 的动态系统颜色,它们会自动跟随外观变化:

// Colorful/Classes/ColorMapView.swift 中的 updateStrokeColor() let separatorColor: UIColor if #available(iOS 13.0, *) { separatorColor = UIColor.tertiarySystemGroupedBackground } else { separatorColor = #colorLiteral(red: 0.894, green: 0.894, blue: 0.894, alpha: 1) }

明度滑条上下两端的阴影渐变色,则使用UIColor.systemBackground打底,低版本回退为白色:

// Colorful/Classes/BrightnessSlider.swift 中的 updateShadowColor() if #available(iOS 13.0, *) { bgColor = UIColor.systemBackground } else { bgColor = UIColor.white }

#available的版本判断,让库在 iOS 10 老系统上也能优雅降级——这一点在 Colorful.podspec 中也能印证,它的部署目标是 iOS 10.0。✅

关键一步:用 traitCollectionDidChange 拦截主题切换

系统动态颜色能解决 UILabel、UIView 背景色的自动更新,但CALayer 上的strokeColorcolors这些 CGColor 是静态快照,不会自己变。Colorful 的解法非常克制——在需要刷新的视图里重写一个方法:

// Colorful/Classes/ColorMapView.swift (L101-L104) override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) updateStrokeColor() }

BrightnessSlider里是同样的模式,只是多刷新了阴影渐变色:

// Colorful/Classes/BrightnessSlider.swift (L102-L106) override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) updateBorderColor() updateShadowColor() }

这个方法就是 UIKit 在用户切换明暗主题(以及尺寸类、对比度等特征变化)时自动回调的钩子。用它的好处:

  • 零手动监听:不用注册NSNotification,不存在注册晚、泄漏、忘记注销的问题;
  • 刷新范围最小化:谁需要变色,谁自己重写,ColorMapView只刷描边,BrightnessSlider只刷边框和阴影,互不干扰;
  • 时机精准:回调时视图已经处于新外观上下文里,此时读取UIColor.tertiarySystemGroupedBackground拿到的就是深色值。

一个容易被忽略的细节:切换瞬间禁用动画

注意 Colorful 在更新 Layer 颜色时都包了一层:

CATransaction.begin() CATransaction.setDisableActions(true) backgounrdLayer.strokeColor = separatorColor.cgColor CATransaction.commit()

CACurrentTransaction默认会给属性变化加 0.25 秒隐式动画。主题切换的瞬间如果让描边颜色"慢慢渐变过去",视觉上会显得拖沓。setDisableActions(true)让颜色瞬时完成切换,和系统整体外观翻转同步——这个细节让深色模式的切换体验浑然一体。✨

快速上手:把 Colorful 集成到你的项目

Colorful 支持 CocoaPods,安装只需两步:

# Podfile platform :ios, '10.0' pod "Colorful", "~> 3.0"
$ pod install

也可以直接克隆仓库查看示例工程(Example/目录下有完整的 Demo):

git clone https://link.gitcode.com/i/4f11983383d604761f793468ae18d915

基本用法如下,切换颜色时会收到.valueChanged事件:

let colorPicker = ColorPicker(frame: ...) colorPicker.addTarget(self, action: #selector(colorChanged), for: .valueChanged) colorPicker.set(color: .red, colorSpace: .extendedSRGB) view.addSubview(colorPicker)

ColorPicker本体定义在Colorful/Classes/ColorPicker.swift,它对深色模式是"透明"的——外观切换完全由内部子视图各自处理,调用方什么都不用做。🎨

照猫画虎:自己项目里适配深色模式的 3 条清单

把 Colorful 的做法提炼出来,就是三步:

  1. 装饰色优先用系统动态颜色(如tertiarySystemGroupedBackgroundsystemBackground),并给老系统留#colorLiteral回退;
  2. 给每个持有 Layer 的视图重写traitCollectionDidChange,记得先调super,只刷新自己负责的属性;
  3. CATransaction.setDisableActions(true)包裹颜色更新,让切换瞬时生效。

深色模式适配的本质不是"多写一遍深色 UI",而是让颜色随上下文自动流动。Colorful 用不到 20 行代码就完成了这件事,干净、克制,值得作为你的参照模板。

【免费下载链接】Color-Picker-for-iOSColorful: iOS color picker built with Swift.项目地址: https://gitcode.com/gh_mirrors/co/Color-Picker-for-iOS

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/22 14:37:57

从手机里提取已安装应用的APK:Kanade免费搞定备份与分享

从手机里提取已安装应用的APK:Kanade免费搞定备份与分享 【免费下载链接】kanade Android app to extract apks from installed apps. 项目地址: https://gitcode.com/gh_mirrors/ka/kanade 想把手机里的应用发给朋友,或重装系统前留个备份&#…

作者头像 李华
网站建设 2026/8/22 14:33:13

Akagi 雀魂AI辅助完整教程:免费实时分析,4 步跑起来

Akagi 雀魂AI辅助完整教程:免费实时分析,4 步跑起来 【免费下载链接】Akagi 支持雀魂、天鳳、麻雀一番街、天月麻將,能夠使用自定義的AI模型實時分析對局並給出建議,內建Mortal AI作為示例。 Supports Majsoul, Tenhou, Riichi Ci…

作者头像 李华