iOS 实现主题切换,相信在未来的app里也是会频繁出现的,尽管现在只是出现在主流的APP,如(QQ、新浪微博、酷狗音乐、网易云音乐等),但是现在是看颜值、追求个性的年代,所以根据用户喜好自定义/切换主题也是未来app的必备功能了。
为了降低耦合度,决定采用的方案是使用NSObject的分类来实现主题设置,有些读者可能会想为何不使用UIView的分类而是使用NSObject的分类?建议这部分读者看一下UIBarItem父类,然后仔细思考一下,就会理解了。
设置主题色
- 创建主题色池
- 将需要设置主题色的控件及其对应属性/方法添加到主题色池中
- 调用设置主题色方法时,遍历主题色池中的控件,使用KVC设置对应属性或调用对应的方法来实现主题色的设置
代码实现
建议读者在理解思路以后先下载源码大概看一下(纵观全局)再阅读以下内容:
源码地址:github.com/iphone5solo…
1. 创建主题色池
由于是在NSObject的分类里面创建,为了方便管理,设置全局变量_themeColorPool,并通过懒加载完成_themeColorPool的实例化。数组中的对象原来采用的是NSDictionary,但是由于NSDictionary存储时,会对对象采用强引用导致对象不能被及时释放,所以最终采用的解决方案是采用NSMapTable存储,实现对象的弱引用,详情见下一步就会理解了
2. 添加控件到主题色池中
由于颜色设置有的可以直接通过属性设置也有的需要通过调用方法才可设置。以UIButton为例,设置背景色可通过属性button.backgroundColor设置,设置选中状态时的字体颜色则要调用setTitleColor:forState:方法才可设置,于是,就得提供两个方法供使用者调用,如下
实现如下:
为了满足个别需求,所以还是提供一下从主题色池中移除控件的方法
实现如下:
3. 设置主题色
实现如下:
使用
假设有个需求:UINavigationBar的背景颜色和UIButton选中时的字体颜色会随着主题颜色的变化而变化,实现如下:
将navigationBar的background和UIButton的setTitleColor:forState:方法添加到主题池中,方法参数中如果是设置为主题色的参数则用PYTHEME_THEME_COLOR占位,如果参数为nil,则使用[NSNull null]代替
设置主题色
这里有一点注意的是[object py_performSelector:selector withObjects:args];这是自己实现的performSelector 多参调用关于这方面的网上已经有很多教程了,这里就不多介绍了。直接附上的我实现(内部方法,主要考虑到自己的使用):
细节处理
1. 设置主题色的方式
- 通过属性直接设置主题色
- 通过调用方法并以主题色为参数来设置主题色
- 通过调用方法但主题色被封装后(如:NSDictionary)作为参数设置主题色
2. 自动管理内存管理
当对象应该被释放后,下一次当主题色池有新元素添加时,会遍历主题色池,根据对象的引用计数来决定是否移除对象(实现自动管理内存),因此:主题色池中最多可能会残留一个对象,这对内存几乎没有任何影响,如果要及时释放对象本人认为可以采用KVO监听对象的引用计数(未尝试),但是耗能高,不建议这么做!
3. 当对象为_UIAppearance类时,不添加到主题色池
了解UIAppearance的读者应该可以理解,而且使用UIAppearance的目的也为为了设置全局色,所以为了避免冲突,如果使用了该“技术”就不添加到主题色池
设置主题图片
观察了新浪微博、酷狗音乐等app,发现设置主题图片还是很有必要的,而且发现每套主题皮肤/图片都有对应的主题色,所以在设计接口的时候都考虑了这方面的需求。先看一下设置主题图片的基本原理,如下:
- 创建一个主题图片池(使用懒加载)
- 将相关控件对象直接添加到主题图片池中
- 设置主题图片时,通过block把主题图片池中的所有对象传递给用户,用户实现block,在block中获得对象,并根据需求设置相关属性完成主题图片的设置
####代码实现:
1. 创建一个主题图片池(使用懒加载)
2. 添加相关控件到主题图片池中
因为在设置图片是,比较复杂,如UITabBar上面的UIBarItem的图片、字体颜色等,所以为了满足大部分用户的需求,决定采用的是直接存储控件对象
实现如下:
3. 设置主题图片和相关配色
当设置图片时,会通过block将主题图片池里面的所有控件传递给用户,用户根据需求进行相关设置,如果提供了配色,就会采用上面设置主题色功能来设置主题色
实现如下:
使用
假设现在有这么一个需求:更换主题图片时,更换UITabBarItem的图片
- 将UITabBarItem添加到图片池
- 切换主题图片并设置配色为红色
总结
篇幅可能有点大,能耐心读到这里的读者相信会有不少收获的,希望读者在阅读此教程的时候,千万不要学习代码实现,而是要多思考:为什么要这样实现?那样实现有什么不好?多学学接口为什么要这样设计,那样设计是不是更合理?当你带着这些问题再回过头来去看看源码时,希望你会有更多的收货!当然,这里只是提供了一种思路,你也可以在此基础上实现夜间模式的切换等。期待你们的实现!
期望
当然如果您有更多的想法想表达或者交流的话,欢迎到留言/评论!因为本人比较喜欢活跃在GitHub社区,所以,如果您有什么想反馈的也可以issuse me,在这也鼓励大家去多多发现优秀源码,并且共享给大家。毕竟分享是双方获利的,何乐而不为?
源码地址:github.com/iphone5solo…
源码作者:CoderKo1o