推广 热搜: page  音视频  使用  选择  搜索引擎  百度  企业  可以  个数  父亲 

iOS实现换肤功能的简单处理框架(附源码)

   日期:2025-01-03     作者:czdytfhm4    caijiyuan   评论:0    移动:http://ww.kub2b.com/mobile/news/19598.html
核心提示:前言换肤功能是在APP开发过程中遇到的比较多的场景,为了提供更好的用户体验,许多APP会为用户提供切换主题的功能。主题颜色管理

前言

换肤功能是在APP开发过程中遇到的比较多的场景,为了提供更好的用户体验,许多APP会为用户提供切换主题的功能。主题颜色管理涉及到的的步骤有

  • 颜色配置
  • 使用颜色
  • UI元素动态变更的能力
  • 动态修改配置
  • 主题包管理
  • 如何实施
  • 优化

效果如下:

DEMO代码:https://gitee.com/dhar/iosdemos/tree/master/YTThemeManagerDemo

颜色配置

因为涉及到多种配置,所以以代码的方式定义颜色实践和维护的难度是比较高的,一种合适的方案是--颜色的配置是通过配置文件的形式进行导入的。配置文件会经过转换步骤,最终形成代码层级的配置,以全局的方式提供给各个模块使用,这里会涉及到一个颜色管理者的概念,一般地这回事一个单例对象,提供全局访问的接口。同一个APP中在不同的模块中保存不同的主题颜色配置,在不同的层级中也可以存在不同的主题颜色配置,因为涉及到层级间的配置差异,所以颜色的配置需要引入一个等级的概念,一般地较高层级颜色的配置等级是高于较低层级的,存在相同的配置较高层级的配置会覆盖较低层级的配置。

我们采用的颜色配置的文件形如下面所示,为什么是在一个json文件的colorkey下面呢,是为了考虑到未来的扩展性,如果不同的主题会涉及到一些尺寸值的差异化,我们可以添加dimensionskey进行扩展配置。

有了以上的配置,颜色配置的工作主要就是解析该配置文件,把配置保存在一个单例对象中即可,这部分主要的步骤如下:

  • 配置文件类表根据等级排序
  • 获取每个配置文件中的配置,进行保存
  • 通知外部主题颜色配置发生改变

对应的代码如下,这里有个需要注意的地方是,加载配置文件的时候使用了文件读写锁进行读写的锁定操作,防止读脏数据的发生,直到配置文件加载完成,释放读写锁,这时读进程可以继续。

管理者处理处理配置之外,还需要暴露外部接口给客户端使用,以用于获取不同主题下对应的颜色色值、图片资源、尺寸信息等和主题相关的信息。比如我们会提供一个colorForKey方法获取不同主题下的同一个key对应的颜色色值,获取色值的大致步骤如下:

  • 从当前的主题配置中获取
  • 从默认的主题配置中获取
  • 从预留的主题配置中获取
  • 如果重定向的配置,递归处理
  • 以上步骤都完成还未找到返回默认黑色

这里使用了读写锁的写锁,如果同时有写操作获取了该锁,读取进程会阻塞直到写操作的完成释放锁。

使用颜色

颜色的使用也是经由管理者的,为了方便,定义一个颜色宏提供给客户端使用

客户端使用的代码如下:

另外,因为颜色配置的key为字符串类型,直接使用字符串常量并不是个好办法,所以把对应的字符串转换为宏定义是一个相对好的办法。第一个是方便使用,可以使用代码提示;第二个是不容易出错,特别是长的字符串;第三个也会一定程度上的提高效率。

YTColorDefine类的宏定义

主题包管理

在实际的落地项目中,主题包管理涉及到的事项包括主题包下载和解压和动态加载主题包等内容,最后的一步是更换主题配置文件所在的配置路径,为了演示的方便,我们会把不同主题的资源放置在bundle中某一个特定的文件夹下,通过切换管理者中的主题路径配置来达到切换主题的效果,和动态下载更换主题的步骤是一样的。

管理者提供一个设置主题配置的配置路径的方法,在该方法中改变配置路径的同时,重新加载配置即可,代码如下

如何实施

以上的流程涉及到的只是iOS平台下的一个技术解决方案,真实的实践过程中会涉及到安卓平台、Web页面、UI出图的标注,这些是要进行统一处理的,才能在各个端上有一致的体验。第一步就是制定合理的颜色规范,把规范同步给各个端的利益相关人员;第二部是UI出图颜色是规范的颜色定义值,而不是比如#ffffff这样的颜色,需要是比如White_A这样规范的颜色定义值,这样客户端处理使用的就是White_A这个值,不用管在不同主题下不同的颜色表现形式。

优化

loadConfigDataWithColorMap方法调用的优化

如果模块很多,每个模块都会调用loadConfigWithFileName加载配置文件,那么loadConfigDataWithColorMap方法处理文件的时间复杂度是O(N*N),会重复处理很多多余的工作,理想的做法是底层保存一份公有的颜色配置,然后在APP层加载一份定制化的配置,在模块中不用再加载主题配置文件,这样会提高效率。

附:读写锁pthread_rwlock_t的使用

读写锁是用来解决读者写者问题的,读操作可以共享,写操作是排他的,读可以有多个在读,写只有唯一个在写,同时写的时候不允许读。

具有强读者同步和强写者同步两种形式

强读者同步:当写者没有进行写操作,读者就可以访问;

强写者同步:当所有写者都写完之后,才能进行读操作,读者需要最新的信息,一些事实性较高的系统可能会用到该所,比如定票之类的。

读写锁的操作:

读写锁的初始化:

        定义读写锁:          pthread_rwlock_t  m_rw_lock;

        函数原型:              pthread_rwlock_init(pthread_rwlock_t * ,pthread_rwattr_t *);

        返回值:0,表示成功,非0为一错误码

读写锁的销毁:

        函数原型:             pthread_rwlock_destroy(pthread_rwlock_t* );

        返回值:0,表示成功,非0表示错误码

获取读写锁的读锁操作:分为阻塞式获取和非阻塞式获取,如果读写锁由一个写者持有,则读线程会阻塞直至写入者释放读写锁。

        阻塞式:

                            函数原型:pthread_rwlock_rdlock(pthread_rwlock_t*);

        非阻塞式:

                            函数原型:pthread_rwlock_tryrdlock(pthread_rwlock_t*);

       返回值: 0,表示成功,非0表示错误码,非阻塞会返回ebusy而不会让线程等待

获取读写锁的写锁操作:分为阻塞和非阻塞,如果对应的读写锁被其它写者持有,或者读写锁被读者持有,该线程都会阻塞等待。

      阻塞式:

                           函数原型:pthread_rwlock_wrlock(pthread_rwlock_t*);

      非阻塞式:

                           函数原型:pthread_rwlock_trywrlock(pthread_rwlock_t*);

       返回值: 0,表示成功

释放读写锁:

                         函数原型:pthread_rwlock_unlock(pthread_rwlock_t*);

总结(转):

互斥锁与读写锁的区别:

当访问临界区资源时(访问的含义包括所有的操作:读和写),需要上互斥锁;

当对数据(互斥锁中的临界区资源)进行读取时,需要上读取锁,当对数据进行写入时,需要上写入锁。

读写锁的优点:

对于读数据比修改数据频繁的应用,用读写锁代替互斥锁可以提高效率。因为使用互斥锁时,即使是读出数据(相当于操作临界区资源)都要上互斥锁,而采用读写锁,则可以在任一时刻允许多个读出者存在,提高了更高的并发度,同时在某个写入者修改数据期间保护该数据,以免任何其它读出者或写入者的干扰。

读写锁描述:

获取一个读写锁用于读称为共享锁,获取一个读写锁用于写称为独占锁,因此这种对于某个给定资源的共享访问也称为共享-独占上锁。

有关这种类型问题(多个读出者和一个写入者)的其它说法有读出者与写入者问题以及多读出者-单写入者锁。

总结

本文地址:http://ww.kub2b.com/news/19598.html     企库往 http://ww.kub2b.com/ ,  查看更多

特别提示:本信息由相关用户自行提供,真实性未证实,仅供参考。请谨慎采用,风险自负。

 
 
更多>同类最新文章
0相关评论

文章列表
相关文章
最新动态
推荐图文
最新文章
点击排行
网站首页  |  关于我们  |  联系方式  |  使用协议  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报  |  鄂ICP备2020018471号