iOS android 色彩管理,iOS应用主题(图片,颜色)统一管理

// 2017.8.24 更新

进阶篇:再谈 Swift 换肤功能,看完该文后强烈建议看下进阶篇,彩蛋彩蛋彩蛋哦。

在我过去的一个多月里,发现很多不愉快的事情,导致 OpenGL SE系列的文章好久没有更新了,今天来分享下以前做的主题管理来做一个新开始,OpenGL SE的文章会继续坚持写下去,欢迎关注。

只需@3x图片

现在工作改做SDK后,发现很少和界面相关的东西打交道了,但做过APP的同学们都应该知道,为了适应各种屏幕的尺寸,图片资源需要提供@1x、@2x和@3x来适配屏幕界面,现在基本没有 1x屏幕的设备了,可以不用提供这个分辨率的图片了。但@2x和@3x可以说是重复的资源,这只会增大应用包的大小。

865e4f72957a

C69924BD-2C0E-4279-A4EB-3D822C5AB340.png

在这,我只使用@3x的图片来做适配:

先写在前面,iOS 8后系统自动会将@3x图片自动适配图片,也就是说你的应用不支持iOS 8以下系统的话,你可以直接使用@3x的资源就可以了,你可以直接跳过这一节。

这里为了实现换肤功能,所有的资源我都会存在Bundle里面,首先解释下,Bundle是静态的,作为一个资源包是不参加项目编译的,也就是说,bundle包中不能包含可执行的文件,它仅仅是作为资源,被解析成为特定的2进制数据。对于在iOS 8系统上会自动将@3x的资源自动适配后,我们只需要考虑iOS 8下的系统,这个时候我们只需要手动去重新绘制图片的大小(比较消耗性能的动作),实现如下:

Swift:

private func scaledImageFrom3x() -> UIImage {

let locScale = UIScreen.mainScreen().scale

let theRate: CGFloat = 1.0 / 3.0

let oldSize = self.size

let scaleWidth = CGFloat(oldSize.width) * theRate

let scaleHeight = CGFloat(oldSize.height) * theRate

var scaleRect = CGRectZero

scaleRect.size.width = scaleWidth

scaleRect.size.height = scaleHeight

UIGraphicsBeginImageContextWithOptions(scaleRect.size, false, locScale)

drawInRect(scaleRect)

var newImage = UIImage()

newImage = UIGraphicsGetImageFromCurrentImageContext()

UIGraphicsEndImageContext()

return newImage

}

OC:

- (UIImage *)scaledImageFrom3x

{

float locScale = [UIScreen mainScreen].scale;

float theRate = 2.0 / 3.0;

UIImage *newImage = nil;

CGSize oldSize = self.size;

CGFloat scaledWidth = oldSize.width * theRate;

CGFloat scaledHeight = oldSize.height * theRate;

CGRect scaledRect = CGRectZero;

scaledRect.size.width = scaledWidth;

scaledRect.size.height = scaledHeight;

UIGraphicsBeginImageContextWithOptions(scaledRect.size, NO, locScale);

[self drawInRect:scaledRect];

newImage = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

if(newImage == nil) {

NSLog(@"could not scale image");

}

return newImage;

}

换肤功能

换肤功能,其实就是图片和颜色等资源的切换,也就是说你有几套皮肤,就提供对应的几套资源,当切换皮肤的时候,切换资源访问的路径并发出要换肤的通知,当前界面监听换肤的通知后再去刷新界面就完成了换肤的功能了。

我们实现一个ThemeManager的主题管理类,应用的所有资源访问都通过这个类来实现统一管理,所有的主题基本上都是由颜色和资源(图片,音频,文本等)来决定的,所以换肤时只要更改主题颜色库(themeColors)和主题资源库(themeBundle),实现如下:

Swift:

class CPThemeManager: NSObject {

private var themeStyle: CPThemeType?

private var themeBundle: NSBundle?

private var themeColors: Dictionary?

// MARK: 单例

static let shareInstance = CPThemeManager()

private override init() {}

}

OC:

static BTThemeManager * _themeManager = nil;

@interface BTThemeManager () {

NSDictionary *_themeColors;

}

@property (nonatomic, strong) NSDictionary *themeColors;

@property (nonatomic, strong) NSBundle *themeBundle;

@end

@implementation BTThemeManager

@synthesize themeStyle = _themeStyle;

@synthesize themeColors = _themeColors;

+ (BTThemeManager *)getInstance

{

static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{

_themeManager = [[BTThemeManager alloc]init];

});

return _themeManager;

}

- (id) init

{

if (self = [super init]) {}

return self;

}

@end

上面也说了,换肤实质只是更换资源访问的路径,所以提供一个设置主题的方法来进行资源路径的设置(setThemeStyle),在重新设置完资源路径后,再对外发出更新界面的通知,实现如下:

Swift:

func setThemeStyle(themeStyle: CPThemeType) {

//设置资源路径

NSNotificationCenter.defaultCenter().postNotificationName("CPThemeChangeNotification", object: nil)

}

OC:

- (void)setThemeStyle:(BTThemeType)themeStyle

{

if (_themeStyle == themeStyle ) {

return;

}

_themeStyle = themeStyle;

//设置资源路径

[[NSNotificationCenter defaultCenter] postNotificationName:BTThemeChangeNotification object:nil];

}

下面将说整个主题管理功能的最重要一步:监听主题的切换。

首先定义一个需要更新主题的协议方法:

Swift:

protocol CPThemeListenerProtocol {

func CPThemeDidNeedUpdateStyle() -> Void

}

OC:

@protocol BTThemeListenerProtocol

- (void) BTThemeDidNeedUpdateStyle;

@end

然后在主题管理理里面添加一个注册监听主题切换方法:

Swift:

func addThemeListener(object: CPBaseViewController) {

NSNotificationCenter.defaultCenter().addObserver(object,

selector:#selector(object.CPThemeDidNeedUpdateStyle),

name: "CPThemeChangeNotification",

object: nil)

}

func removeThemeListener(object: AnyObject) {

NSNotificationCenter.defaultCenter().removeObserver(object)

}

因为Swift selector现在只能通过类名.方法名来设置,导致如果要使用则必须要继承一个基类,如果你们有更好的方法,求分享下。

OC:

- (void)addThemeListener:(id )obj

{

if([obj respondsToSelector:@selector(BTThemeDidNeedUpdateStyle)]){

[[NSNotificationCenter defaultCenter] addObserver:obj selector:@selector(BTThemeDidNeedUpdateStyle) name:BTThemeChangeNotification object:nil];

}

}

- (void) removeThemeListener:(id)obj

{

if (obj) {

[[NSNotificationCenter defaultCenter] removeObserver:obj];

}

}

最后在要实现主题切换的页面里添加主题管理类的监听切换方法,并实现协议的方法,把需要做主题切换的资源访问都放在这个方法里面,然后就搞定啦。搞了?好像少了点什么,还没有说如何去访问资源呢,这个我想大家都能自己去去实现,就是在基类里实现一个统一访问资源的方法:

- (void )BTThemeImage:(NSString *)imageName completionHandler:(void (^)(UIImage *image))handler;

{

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

// 耗时的操作

NSString *imagePath = [NSString stringWithFormat:@"image/%@",imageName];

UIImage *image = nil;

//通过资源路径去访问

if (image == nil) {

image = [UIImage imageNamed:imageName];

}

dispatch_async(dispatch_get_main_queue(), ^{

// 更新界面

handler(image);

});

});

}

写在最后:欢迎大家一起多交流多学习,有更好的想法实现什么的, 求分享~~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值