iOS 项目中的多主题颜色设计与实现

引言
在现代iOS应用中,用户对个性化体验的需求越来越高,除了功能上的满足,多样的视觉风格也是提升用户体验的重要手段之一。提供多主题颜色的切换功能不仅能满足用户的审美偏好,还可以让应用更具活力,适应不同场景下的使用需求。列好的主题切换设计能提升应用的整体品质。
在这篇博客中,我将分享一个简单而灵活的多主题颜色管理方案,我们将通过使用工厂模式和协议的组合,实现不同主题颜色的管理与切换功能。无论是为应用提供个性化的主题颜色,还是为了后续的主题扩展,这种设计都能为项目带来更好的可维护性和扩展性。
主题颜色切换架构概述
为了实现多主题颜色管理,我们采用了工厂模式与协议模式的组合。通过定义个通用的颜色协议(ZMColorFactory),我们可以为不同的主题提供一致的接口,同时保证代码的灵活性和可扩展性。每个主题的颜色实现由独立的工厂类负责,根据用户选择或应用内的设置来动态切换主题。这种设计不仅能有效地管理不同的主题颜色,还可以轻松扩展未来的新主题。
项目额整体架构可以分为以下几部分:
颜色工厂协议
颜色工厂协议定义了不同主题颜色所需的接口,例如主题颜色,文字颜色等。所有的颜色工厂都应该遵循该协议,确保各个主体能够提供一致的颜色属性。
颜色工厂
每个主题的颜色工厂类实现了颜色工厂的协议,提供具体的颜色值。例如,红色主题工厂提供红色的主题颜色,而蓝色的主题工厂则提供蓝色的主题和文字颜色。
主题管理器
主题管理器是整个架构的核心,负责根据用户选择或系统设置来切换主题。通过主题管理器,我们可以动态地从不同的颜色工厂中获取当前主题的颜色。
主题切换功能
主题管理器能够根据用户偏好或者其它逻辑比如启动时的默认主题,在不同的颜色工厂之间切换。当主题切换时,应用的颜色会即时更新,提升用户体验。
主题颜色切换文件介绍

主题枚举
在我们实现多主题管理的过程中,首先需要定义一个枚举来表示不同的主题类型。在ZMTheme文件中,我们定义了一个ZMTheme枚举,用于列举所有可用的主题。为了简化示例代码,我们只定义了两个主题:红色和蓝色。当然实际项目中可以根据需求添加更多主题。
enum ZMTheme {/// 红色主题case red/// 蓝色主题case blue
}
这个枚举将用于在应用中表示用户所选择的主题,并通过主题管理器根据该枚举值来切换不同的主题工厂,从而实现主题颜色的动态更新。
颜色工厂协议
为了确保每个主题能够提供一致的颜色方案,我们定义了一个颜色工厂协议ZMColorFactory。这个协议为每个主题提供了统一的接口,规定了所有主题都必须包含的颜色属性。通过这种方式,不同主题可以根据各自的风格实现自己的颜色,但依然遵循同样的接口,从而保证在应用中不同主题的颜色切换能够无缝衔接。
ZMColorFactory协议的定义如下:
protocol ZMColorFactory {/// 主题的主色调var themeColor: UIColor { get }/// 标题文字颜色var titleColor: UIColor { get }....
}
同样为了简洁我们在协议中定义了两个基本的颜色属性:
- themeColor:每个主题的主色调,通常用于页面的导航栏,按钮颜色等等。
- titleColor:用于显示大标题文字的颜色。
通过这个协议,我们可以确保每个主题工厂都能提供这些颜色属性。这样,在后续的主题工厂实现中,不同的主题只需要实现这个协议即可提供自己的特定的颜色方案,而主题管理器则可以通过这个统一接口轻松地访问这些颜色。
颜色工厂
在定义了ZMColorFactory协议之后,我们通过不同的工厂类来实现各个主题的具体颜色方案。每个工厂类复杂提供一套完整的颜色配置,这样可以确保在应用中不同主题的颜色实现能够根据用户的选择动态切换。同样为了简洁,我们定义两个颜色工厂ZMBaseColorFactory和ZMBlueColorFactory。
基础主题工厂
ZMBaseColorFactory是我们项目中的基本主题工厂,它实现了ZMColorFactory协议,并默认的红色主题提供颜色配置:
class ZMBaseColorFactory: NSObject, ZMColorFactory {/// 主题色var themeColor: UIColor {return UIColor.zm_hex("#FB233B")}/// 标题文字颜色var titleColor: UIColor {return UIColor.zm_hex("#333333")}
}
在这个工厂中,我们通过返回固定的颜色值实现了红色主题的主色调和标题文字颜色。主色调是红色(#FB233B),标题文字使用深灰色(#333333)
蓝色主题工厂
ZMBlueColorFactory是另一个实现了ZMColorFactory协议的工厂类,为蓝色主题提供颜色方案:
class ZMBlueColorFactory: NSObject, ZMColorFactory {/// 主题色var themeColor: UIColor {return UIColor.blue}/// 标题文字颜色var titleColor: UIColor {return UIColor.blue}
}
在这个工厂中,我们为蓝色主题提供了主色调和标题文字颜色,简洁起见二者都是用了系统的UIColor.blue。
扩展性
通过这种工厂类的设计,每当我们需要新增一个主题时,只需实现ZMColorFactory协议,并在新的工厂类中定义该主题的颜色属性。这样不仅代码结构清晰,还能保证新旧主题的无缝切换。
主题颜色管理器
为了实现高效的主题管理,我们还需要引入ZMColorHelper类作为主题管理器。该管理器负责整个应用的主题初始化、更新和颜色获取,确保用户的主题选择能够即时反映在应用界面中。
class ZMColorHelper: NSObject {/// 当前颜色工厂static private var colorFactory: ZMColorFactory = ZMBaseColorFactory()/// 启动主题管理器static func startUp() {// 从用户默认设置中读取当前主题if let theme = UserDefaults.standard.object(forKey: "theme") as? ZMTheme {updateTheme(theme: theme)}}/// 更新主题/// - Parameter theme: 主题/// - Returns: Voidstatic func updateTheme(theme: ZMTheme) {switch theme {case .red:colorFactory = ZMBaseColorFactory()case .blue:colorFactory = ZMBlueColorFactory()}// 将当前主题存储到用户默认设置中UserDefaults.standard.set(theme, forKey: "theme")}/// 获取当前主题色static var themeColor: UIColor {return colorFactory.themeColor}/// 标题文字颜色static var titleColor: UIColor {return colorFactory.titleColor}}
启动主题管理器
在startUp()方法中,管理器会从用户的默认设置中读取存储的主题值。如果用户之前选择过主题,管理器会响应地更新当前主题。
更新主题
通过updateTheme(theme:)方法,管理器可以根据传入的主题枚举值来选择不同的颜色工厂。当用户更改主题时,需要对用这个方法。从而更新colorFactory为相应的主题工厂。同时,当前选择的主题也会被存储到用户的默认设置中,以便下次启动应用时能够恢复到上次使用的主题。
获取主题颜色
themeColor和titleColor静态属性返回当前需要获取的颜色,任何需要使用主题颜色的地方都可以通过这些属性来获取。这样,整个应用的颜色管理变得更加集中和简洁。
ZMColorHepler类作为主题管理器,为多主题功能提供了清晰的接口和逻辑,使得主题额管理、更新和颜色获取变得简便而高效。通过集中管理,我们可以确保应用的外观在不同主题间切换时能够无缝衔接,提升用户体验。
颜色扩展
为了简化颜色创建的和管理,我们使用UIColor类扩展了两个使用的方法:zm_rgba和zm_hex。这使得在项目中使用颜色变得更加方便和直观。
extension UIColor {/// RGBA颜色/// - Parameters:/// - r: red/// - g: green/// - b: blue/// - a: alpha/// - Returns: 生成的颜色class func zm_rgba(_ r: CGFloat, _ g: CGFloat, _ b: CGFloat, _ a: CGFloat = 1.0) -> UIColor {return UIColor(red: r / 255.0, green: g / 255.0, blue: b / 255.0, alpha: a)}/// 通过16进制字符串生成颜色/// - Parameters:/// - hex: 16进制字符串/// - alpha: 透明度/// - Returns: 生成的颜色class func zm_hex(_ hex: String, _ alpha: CGFloat = 1.0) -> UIColor {var cString = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()if cString.hasPrefix("#") {cString.removeFirst()}if cString.count != 6 {return UIColor.clear}let rString = String(cString.prefix(2))let gString = String(cString[cString.index(cString.startIndex, offsetBy: 2)..<cString.index(cString.startIndex, offsetBy: 4)])let bString = String(cString.suffix(2))var r: UInt64 = 0, g: UInt64 = 0, b: UInt64 = 0Scanner(string: rString).scanHexInt64(&r)Scanner(string: gString).scanHexInt64(&g)Scanner(string: bString).scanHexInt64(&b)return UIColor(red: CGFloat(r) / 255.0, green: CGFloat(g) / 255.0, blue: CGFloat(b) / 255.0, alpha: alpha)}
}
使用zm_rgba
zm_rgba允许开发者使用红、绿、蓝和透明度值轻松创建颜色。
let customColor = UIColor.zm_rgba(255, 50, 50, 1.0) // 创建一个不透明的红色
使用zm_hex
zm_hex方法使得通过16进制字符快速创建颜色成为可能,特别对于设计师提供的颜色值。
let hexColor = UIColor.zm_hex("#FB233B") // 创建对应的颜色
使用主题颜色切换功
在实际项目中,使用ZMColorHelper进行主题管理就非常简单。一下是一些基本的使用步骤。
启动主题管理
在应用启动时,首选需要调用startUp()方法来初始化主题管理器。这个方法会检测用户的默认设置并加载之前选择的主题。
// 在应用启动时调用
ZMColorHelper.startUp()
切换主题
要切换主题,只需要调用updateTheme(theme:)方法并传入所需的主题枚举值。管理器会根据传入的主题更新相应的颜色工厂,并保持选择的主题到用户默认设置中。
// 切换到红色主题
ZMColorHelper.updateTheme(theme: .red)// 切换到蓝色主题
ZMColorHelper.updateTheme(theme: .blue)
获取当前主题颜色
在需要使用当前主题颜色的地方,可以通过themeColor属性轻松获取主题的颜色。无论实在设置背景色、文字颜色都可以直接使用。
// 设置视图的背景颜色为当前主题色
view.backgroundColor = ZMColorHelper.themeColor// 设置标题的文字颜色为当前主题的标题色
label.textColor = ZMColorHelper.titleColor
结语
在本文中,我们探讨了如何在iOS项目中实现多主题颜色管理。通过引入ZMColorHelper主题管理器和相关的颜色工厂协议,我们构建了一个灵活且易于扩展的主题系统。无论是通过简单的枚举定义主题,还是通过工厂模式实现颜色的具体化,我们的设计都旨在提供清晰的接口和无缝的用户体验。
随着用户对应用个性化需求的不断增加,支持多主题功能不仅提升了用户体验,还增强了应用的吸引力。希望通过本篇文章,能够帮助开发者更好地理解和实现多主题管理的最佳实现,使我们的应用在视觉效果上更具吸引力。
相关文章:
iOS 项目中的多主题颜色设计与实现
引言 在现代iOS应用中,用户对个性化体验的需求越来越高,除了功能上的满足,多样的视觉风格也是提升用户体验的重要手段之一。提供多主题颜色的切换功能不仅能满足用户的审美偏好,还可以让应用更具活力,适应不同场景下的…...
Android Camera2 与 Camera API技术探究和RAW数据采集
Android Camera2 Android Camera2 是 Android 系统中用于相机操作的一套高级应用程序接口(API),它取代了之前的 Camera API。以下是关于 Android Camera2 的一些主要信息: 主要特点: 强大的控制能力:提供…...
[python][pipenv]pipenv的使用
pipenv 是一个 Python 开发工作流程的工具,它旨在将 pip 的包管理和 virtualenv 的虚拟环境管理结合起来。以下是一些基本的 pipenv 使用方法: 安装 pipenv: 如果你还没有安装 pipenv,可以通过 pip 安装它: pip insta…...
SpringSession微服务
一.在linux中确保启动起来redis和nacos 依赖记得别放<dependencyManagement></dependencyManagement>这个标签去了 1.首先查看已经启动的服务 docker ps 查看有没有安装redis和nacos 2.启动redis和nacos 发现没有启动redis和nacos,我们先来启动它。,…...
强化学习:通过试错学习最优策略---示例:使用Q-Learning解决迷宫问题
强化学习(Reinforcement Learning, RL)是一种让智能体(agent)在与环境交互的过程中,通过最大化某种累积奖励来学习如何采取行动的学习方法。它适用于那些需要连续决策的问题,比如游戏、自动驾驶和机器人控制…...
OpenGL ES 纹理(7)
OpenGL ES 纹理(7) 简述 通过前面几章的学习,我们已经可以绘制渲染我们想要的逻辑图形了,但是如果我们想要渲染一张本地图片,这就需要纹理了。 纹理其实是一个可以用于采样的数据集,比较典型的就是图片了,我们知道我…...
【C#】CacheManager:高效的 .NET 缓存管理库
在现代应用开发中,缓存是提升性能和降低数据库负载的重要技术手段。无论是 Web 应用、桌面应用还是移动应用,缓存都能够帮助减少重复的数据查询和处理,从而提高系统的响应速度。然而,管理缓存并不简单,尤其是当你需要处…...
【数学分析笔记】第4章第2节 导数的意义和性质(2)
4. 微分 4.2 导数的意义与性质 4.2.3 单侧导数 f ′ ( x ) lim Δ x → 0 f ( x Δ x ) − f ( x ) Δ x lim x → x 0 f ( x ) − f ( x 0 ) x − x 0 f(x)\lim\limits_{\Delta x\to 0}\frac{f(x\Delta x)-f(x)}{\Delta x}\lim\limits_{x\to x_0}\frac{f(x)-f(x_0)…...
深度学习:迁移学习
目录 一、迁移学习 1.什么是迁移学习 2.迁移学习的步骤 1、选择预训练的模型和适当的层 2、冻结预训练模型的参数 3、在新数据集上训练新增加的层 4、微调预训练模型的层 5、评估和测试 二、迁移学习实例 1.导入模型 2.冻结模型参数 3.修改参数 4.创建类ÿ…...
Footprint Growthly Quest 工具:赋能 Telegram 社区实现 Web3 飞速增长
作者:Stella L (stellafootprint.network) 在 Web3 的快节奏世界里,社区互动是关键。而众多 Web3 社区之所以能够蓬勃发展,很大程度上得益于 Telegram 平台。正因如此,Footprint Analytics 精心打造了 Growthly —— 一款专为 Tel…...
进入xwindows后挂起键盘鼠标没有响应@FreeBSD
问题: 在升级pkg包后,系统无法进入xfce等xwindows,表现为黑屏和看见鼠标,左上角有一个白字符块,键盘鼠标没有反应,整个系统卡住。但是可以ssh登录,内部的服务一切正常。 表现 处理过程…...
CentOS7.9 snmptrapd更改162端口
端口更改前: 命令: netstat -an |grep 162 [root@kibana snmp]# netstat -an | grep 162 udp 0 0 0.0.0.0:162 0.0.0.0:* unix 3 [ ] STREAM CONNECTED 45162 /run/systemd/journal/stdout u…...
模糊测试SFuzz亮相第32届中国国际信息通信展览会
9月25日,被誉为“中国ICT市场的创新基地和风向标”的第32届中国国际信息通信展在北京盛大开幕,本次展会将在为期三天的时间内,为信息通信领域创新成果、尖端技术和产品提供国家级交流平台。开源网安携模糊测试产品及相关解决方案精彩亮相&…...
CMake学习
向大佬lyf学习,先把其8服务器中所授fine 文章目录 前言一、CMakeList.txt 命令1. 最外层CMakeLists1.1 cmake_minimum_required()1.2 project()1.3 set()1.4 add_subdirectory(&…...
书生·浦语大模型全链路开源开放体系
书生浦语大模型全链路开源开放体系 大模型应用生态的发展和繁荣是建立在模型基座强大的通用基础能力之上的。上海AI实验室联合团队研究认为,大模型各项性能提升的基础在于语言建模能力的增强,对于大模型的研究应回归语言建模本质,通过更高质量…...
PHP安装swoole扩展无效,如何将文件上传至Docker容器
目录 过程 操作方式 过程 在没有使用过云服务器以前,Docker这个平台一直都很神秘。在我申请了华为云服务器,并使用WordPress镜像去搭建自己的网站以后,我不得不去把Docker平台弄清楚,原因是我使用的一个主题需要安装swoole扩展,才能够正常启用。而要将swoole.so这个扩展…...
Web3.0 应用项目
Web3.0 是下一代互联网的概念,旨在去中心化、用户拥有数据控制权和通过区块链技术实现信任的网络。Web3.0的应用项目主要集中在区块链、加密货币、去中心化应用 (DApps)、去中心化金融 (DeFi)、NFT(非同质化代币)等领域。以下是一些典型的 We…...
Linux 学习笔记(十六)—— 重定向与缓冲区
一、文件重定向 矩阵的下标,也就是文件描述符的分配规则,是从0开始空的最小的文件描述符分配给进程新打开的文件;文件输出重定向的原理是,关掉1(输出),然后打开文件,这个新打开的文…...
828华为云征文|WordPress部署
目录 前言 一、环境准备 二、远程连接 三、WordPress简介 四、WordPress安装 1. 基础环境安装 编辑 2. WordPress下载与解压 3. 创建站点 4. 数据库配置 总结 前言 WordPress 是一个非常流行的开源内容管理系统(Content Management System, CMS…...
华为开源自研AI框架昇思MindSpore应用案例:计算高效的卷积模型ShuffleNet
如果你对MindSpore感兴趣,可以关注昇思MindSpore社区 ShuffleNet ShuffleNet网络介绍 ShuffleNetV1是旷视科技提出的一种计算高效的CNN模型,和MobileNet, SqueezeNet等一样主要应用在移动端,所以模型的设计目标就是利用有限的计算资源来达到…...
【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...
【UE5 C++】通过文件对话框获取选择文件的路径
目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 ,这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器,右键点击 .uproject 文件,选择 "Generate Visual Studio project files",重…...
java高级——高阶函数、如何定义一个函数式接口类似stream流的filter
java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用(Math::max) 2 函数接口…...
