iOS端实现节日换肤

article/2025/5/20 10:30:30


本文是我在网上看到一篇不错的文章,因为之前没接触过,所以特意转过来,和大家一起分享下..
以下正文:

一、问题的提出

  不知道大家有没有发现, 元旦期间, 很多APP界面里的图标都换成了具有节日气氛的样式,
而在过了元旦节之后, 这些图标又悄无声息的变回了本来的面貌. 

  这些具有短暂生命周期、而又必须在固定时间节点上展示的节日皮肤, 究竟是如何实现的呢? 显然,
通过发布新版本可以实现, 但是对于iOS端的应用来说, 面对苹果APP
Store不确定的审核时间, 开发人员往往需要提前1~2周完成并提交审核, 而且每到一个节日都要重新发布一个新版本,
难免略显被动. 

热更新是一个不错的选择! 

  试想一下, 如果把需要更换皮肤主题的所有界面元素抽象出一个完整的业务模型(Model), 再由一个专门的Skin
Manager去负责每次启动时的验证和异步加载, 那么以后所有的节日皮肤的发布, 我们都只需要后台改一个参数, 就能够使用户的APP即时的更新到最新的皮肤主题了. 

  当然, 如果你的应用是采用的React Native的话,
换肤就更简单了, 不过呢, 本文是对iOS原生应用提出一套普遍通用的解决方案,
仅仅是抛砖引玉, 如果你有更优化的方案, 欢迎留言提出, 大家共同探讨学习.

  好的, 那我们接下来 试着玩一玩~



二、业务流程

  做一件事之前, 要先理清思路, 做什么、怎么做,
既然方向已经确定下来了, 那么需要梳理一下头绪, 我整理出这么一个流程图:



三、开敲代码

  其实流程图中的每一个方块就是我们需要的方法, 一一实现即可.

  请求接口, 判断, 有三种情况, 删除操作用NSFilemanafer, 下载用AFnetworking, 解压缩用到SSZipArchive这都没什么好说的, 直接上代码就可以了. 

  这其中有一点值得讨论, 就是最后加载皮肤的方式, 我一开始设想的用KVO,
后来发现NotificationCenter会方便一些, 但是还是会很复杂, 如果要修改的皮肤很多,
涉及到的文件也很多, 难道每一个都要都要去注册一个通知中心和一个接收方法吗? 还是有点复杂, 乔帮主说做事要化繁为简,
于是闭上眼睛冥想了一阵, 突然想到了一个方法, 把imageNamed:和colorWith两个基本方法进行替换,
在manager里写两个对应的新方法, 替换掉需要换肤的图片或者文字颜色部分的系统方法, 新方法里面加一个判断,
如果资源文件路径存在, 则显示资源路径下的图片或者解析到的颜色值; 如果资源路径不存在, 则读取默认bundle下的资源.
这样一来, 只需要在原来庞大的工程文件中找到需要修改皮肤的地方, 把他们原来的方法替换就OK了,
节省了很多事, 而且减少暴露在manager外面的逻辑代码, 对于维护也很重要!
好的, 直接上代码:

下面的这个是单例里的两个方法, 专门用来替换需要换肤的组件的原先的方法, 看起来很简洁:

- (UIImage*)imageNamedAutoMatch:(NSString *)name
{return [UIImage imageWithContentsOfFile:_currentPath];
}
- (UIColor*)colorAutoMatch:(NSString *)itemName
{return [UIColor colorWithHexString:_colorArray[itemName]];
}



头文件是这样的, 常用路径写到宏里:

#define Name_Resource @"HolidaySkin"
#define DocumentPath [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:Name_Resource]
#define Bundle_Path [[NSBundle mainBundle]resourcePath]
#define kRequestData /*相应的入参*/@interface DRSkinManager : NSObject@property (nonatomic, copy)NSString *skinStatus;
@property (nonatomic, copy)NSString *downloadUrl;
@property (nonatomic, copy)NSString *currentPath;
@property (nonatomic, strong)NSArray *colorArray;+ (instancetype)shareManager;- (UIImage*)imageNamedAutoMatch:(NSString *)name;
- (UIColor*)colorAutoMatch:(NSString *)itemName;



流程图第一步的接口请求, 没什么好说的:

- (void)checkSkinStatue
{[DRNetwork requestWithDictionary:kRequestData response:^(BOOL success, id result) {if (success) {NSString *skinStaus = result[@"skinStaus"];NSString *downloadUrl = result[@"downloadUrl"];[self judgeResourceStatus:skinStatus url:downloadUrl];}}}];
}



比对状态值, 三种情况, 三个分支:

- (void)judgeResourceStatus:(NSString *)skinStaus url:(NSString *)downloadUrl
{if (skinStaus.length == 0) {return;}NSString *localSkinStatus = [[NSUserDefaults standardUserDefaults]valueForKey:Name_Resource];if ([skinStaus isEqualToString:localSkinStatus]) {self.skinStatus = skinStaus;self.currentPath = [DocumentPath stringByAppendingPathComponent:skinStaus];return;}if (![skinStaus isEqualToString:localSkinStatus]) {if (localSkinStatus.length != 0) {NSFileManager *fileManager = [NSFileManager defaultManager];[fileManager removeItemAtPath:[DocumentPath stringByAppendingPathComponent:localSkinStatus] error:nil];}self.downloadUrl = downloadUrl;[self downLoadAndUnzip];}
}



下载和解压

- (void)downLoadAndUnzip
{NSString *zipPath = [DocumentPath stringByAppendingString:@"/dontcare.zip"];AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]initWithRequest:_downloadUrl];[operation setOutputStream:[NSOutputStream outputStreamToFileAtPath:zipPath append:NO]];[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {//下载成功后: 解压缩[SSZipArchive unzipFileAtPath:zipPath toDestination:[DocumentPath stringByAppendingPathComponent:_skinStatus] progressHandler:^(NSString *entry, unz_file_info zipInfo, long entryNumber, long total){}completionHandler:^(NSString *path, BOOL succeeded, NSError *error){//解压完成, 至此皮肤资源已经完整缓存到沙盒, 删除zip包, 保存skinStatusNSFileManager *fileManager = NSFileManager *fileManager = [NSFileManager defaultManager];[fileManager removeItemAtPath:zipPath error:nil];[[NSUserDefaults standardUserDefaults]setValue:_skinStatus forKey:Name_Resource];}    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {success(operation,error);NSLog(@"下载失败");}];[operation start];
}

 

转载于:https://www.cnblogs.com/Hakim/p/6277212.html


http://chatgpt.dhexx.cn/article/a1pMh3PE.shtml

相关文章

换肤 与 静态库

一 换肤 基本的换肤功能实现选中皮肤保存至系统偏好 // 记录用户选中的皮肤[[NSUserDefaults standardUserDefaults] setObject:skinColor forKey:"skinColor"];[[NSUserDefaults standardUserDefaults] synchronize];123123 抽取SkinTools单例,简化视图…

C++ QT结合FFmpeg实战开发视频播放器-15换肤功能的后台实现

作者:虚幻私塾 博客:https://xuhss.com 早餐店不会开到晚上,想吃的人早就来了!😄 一、换肤功能的后台实现 定义changeBackground函数,让qml去调用这个函数来实现换肤功能, 函数的实现调用了set…

Element UI主题换肤功能(基于vue-element-admin框架)

环境信息: 日期:2022-08-05 node版本:v14.15.4 "sass": "1.26.8", "sass-loader": "8.0.2", 本次实现的是基于花裤衩大佬的 vue-element-admin 或者 vue-admin-template 的前端框架实现的主题换肤功…

JavaScript:演示Ajax的get和post请求,练习选顶卡和换肤案例

JavaScript:演示Ajax的get和post请求,练习选顶卡和换肤案例 Ajax 异步请求 特别提示: 异步请求不要使用live server插件,必须创建一个本地服务器环境 同步与异步 以前端请求,后端响应为例 同步: 前端发请求, 必须等到后端响应完成,才允许发送另一个请求异步: 前端…

Android换肤之Android-skin-support

前言 之前做个APP需要用到换肤,在githup上面找了很久,终于找到一款功能强大、基本能够满足产品需求的换肤框架,那就是Android-skin-support,这个框架换肤功能很强大、不管是白天、黑夜还是任意颜色、图片的皮肤包都可以&#xff…

对 Android 应用换肤方案的总结

作者:me 虽然现在已经有很多不错的换肤方案,但是这些方案或多或少都存在自己的问题。在这篇文章中,我将对 Android 现有的一些动态换肤方案进行梳理,对其底层实现原理进行分析,然后对开发一个新的换肤方案的可能性进行…

前端换肤,聊一聊主题切换那些事

一些网站通常会提供白天、夜间模式,以及自定义主题等等,这种主题切换也就是本文说的前端换肤。 这次案例用的是白天和夜间模式的切换,在做换肤之前,得先知道一件事情:css的变量定义,对变量定义不熟悉的同学…

android 皮肤,Android换肤

前言 之前做个APP需要用到换肤,在githup上面找了很久,终于找到一款功能强大、基本能够满足产品需求的换肤框架,那就是Android-skin-support,这个框架换肤功能很强大、不管是白天、黑夜还是任意颜色、图片的皮肤包都可以&#xff0…

Android 应用换肤方案的总结

虽然现在已经有很多不错的换肤方案,但是这些方案或多或少都存在自己的问题。在这篇文章中,我将对 Android 现有的一些动态换肤方案进行梳理,对其底层实现原理进行分析,然后对开发一个新的换肤方案的可能性进行总结。 1、通过自定…

Android 插件化换肤方案

效果 实现流程 实现LayoutInflater.Factory2这个接口,实现onCreateView方法(主要仿照系统原来LayoutInflater.createView()方法的实现),此处可以拿到页面中所有的View,判断有没有需要换肤的View,并且保存下来;在Activ…

墨迹天气桌面挂件换肤分析

该篇文章需要准备如下工具: 1、墨迹皮肤文件,下载地址。 Andorid换肤在网上搜索出来的结果,大概有三种: 1、应用本身带有写好的布局 优点:开发难度低 缺点:灵活性低,用户不能自定义皮肤。 2、使…

前端换肤的一些思考

先看看大家怎么做的。下面是两篇别人写的文章,最后是我自己的方法。 第一篇:聊一聊前端换肤 之前在做网站换肤,所以想谈谈网站换肤的实现。网页换肤就是修改颜色值,因此重点就在于怎么来替换。 一般实现 如上图,我们…

Visio保存为网页出错

visio 试图保存文档时出错。已创建的页面可能无效。 试图保存文档时出错。以创建的页面可能无效。最近在用Visio作图的时候时长发生的问题。 经过摸索,不覆盖保存没有问题,如果覆盖保存,有时会有这个问题。解决办法就是把以前生成的网页和相关…

Visio 2016软件

Visio 2016是微软官方最新发布的一款领先的图表解决方案,它可以帮助企业制作定义流程、编辑最佳方案的同时还可以建立可视化计划变革的一款实用工具。这款软件目前提供了:上手图例(starter diagrams)、成百上千的智能形状、一步数…

解决visio和office365冲突,无法安装visio问题

本教程用于解决office365和visio冲突,无法安装visio问题 目前系统中已经安装Office365 尚未安装visio专业版本 1、下载office增强工具。 office增强工具下载地址 右键解压,此处要记得解压的目录(建议在当前目录下)。 根据自…

Visio软件

Visio使用小技巧 上标、下标快捷键 上标:CtrlShift“”下标:Ctrl“” 自定义图形旋转角度 当点击菜单栏上的视图——任务窗格——大小和位置选项,在页面编辑区的左下方出现一个大小和位置窗口。 大小和位置窗口如下: 自…

Visio文件编辑查看工具Visio Viewer for Mac

Visio Viewer for Mac可以打开和查看Visio文件(.vsd、.vdx和.vsdm文件)。它具有简单易用的用户界面,可以快速加载和显示Visio文件。此外,它还支持导出文件为PDF、PNG、JPEG等格式,方便用户进行文件转换和共享。 Visio…

与你一起学习Microsoft Visio——基础篇

Hi,你好!我是大黄蜂,非常高兴借此机会与你一起学习MS Visio的相关知识和技能。这一次的分享主要是结合本人在实际使用Visio过程中的一些方法技巧并总结整理其他人分享的知识,其中有一些材料则来源于互联网,期待通过我的…

【Visio】 windows Visio 画图

1、Visio如何画圆形 画圆用 里面的第二个画圆工具 ,用这个工具可以画出圆或者椭圆。如果想得到一个正圆,在画的时候按住shift键即可。 画好一个圆之后单击它,再单击 填充选项,选择你想填充的颜色,选黑色的话就会出现一…

visio2019 专业版,两种方法

安装好visio后,有两种方法jihuo:方法2中自带安装包,有需要可以下载 注意:visio版本要和电脑上带的其他office版本保持一致,否则会不兼容。 1.参考这篇文章,使用代码jihuo https://blog.csdn.net/qq_39400113/article…