简单的界面搭建:
两张图片,一个Switch开关,用来切换图片,用来演示换肤功能
示例代码:
#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView_1;
@property (weak, nonatomic) IBOutlet UIImageView *imageView_2;
@property (weak, nonatomic) IBOutlet UISwitch *nightSwitch;
@end
@implementation ViewController
// 切换夜间模式
- (IBAction)clickNightSwitch:(UISwitch *)sender {
if (sender.isOn) { // switch开启,代表夜间模式
self.imageView_1.image = [UIImage imageNamed:@"baby_night"];
self.imageView_2.image = [UIImage imageNamed:@"girl_night"];
} else {
self.imageView_1.image = [UIImage imageNamed:@"baby"];
self.imageView_2.image = [UIImage imageNamed:@"girl"];
}
}
- (void)viewDidLoad {
[super viewDidLoad];
// 默认关闭 日间模式
[self.nightSwitch setOn:NO];
self.imageView_1.image = [UIImage imageNamed:@"baby"];
self.imageView_2.image = [UIImage imageNamed:@"girl"];
}
@end
实现效果图:
从效果上来看,可以满足基本需求,但是换肤一般针对多界面进行切换,这样只能完成单个界面的换肤,比如再添加一个界面:
默认的ViewController下,是根据一个Switch开关状态来判断日间/夜间模式的,在ViewController重新设置图片后,影响不到其他视图,因为这里使用的是设置图片,所以需要将设置图片操作做处理,模仿imageNamed方法,根据当前的皮肤来做一个判断
实现方式:创建一个UIImage的分类,创建一个设置图片的方法,通过皮肤的标识来设置对应状态下的图片
Switch在ViewController视图下,所以在ViewController中先声明一个全局变量,用作换肤的标识
// 声明全局变量
bool isNight;
在点击Switch开关的时候去给isNight标识赋值
// 赋值
isNight = sender.isOn;
这里演示的换肤只是设置不同的图片,所以需要的结果是UIImage,所以给UIImage添加一个分类,自定义一个设置图片的方法,因为分类中不好添加属性,所以需要使用到上面的全局变量isNight
+ (UIImage *)JSImageNamed:(NSString *)name{
// 判断当前的皮肤
if (isNight) { // 夜间
// 夜间图片命名:日间+_night
name = [NSString stringWithFormat:@"%@_night",name];
}
return [UIImage imageNamed:name];
}
在分类中,根据不同皮肤状态设置图片就需要用到isNight这个标识,在声明以外的类下使用全局变量时,先引用这个全局变量
// 引用全局变量
extern bool isNight;
这样外界设置图片的时候,只需要使用自定义的方法即可:
但目前还有一个问题,当第一次切换到夜间模式后,点击到了Page2页面,图片成功切换,切换Page1页面换回日间模式,再进入到Page2页面,仍然显示夜间模式图片
原因是从Page2切换到Page1界面,Page2 控制器并没有释放,再次切换回Page2时并不会调用ViewDidLoad方法,所以需要将代码写在viewWillAppear中
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
self.imageVIew_3.image = [UIImage JSImageNamed:@"girl"];
}
接下来,需要做本地化处理,记录换肤设置,继续在UIImage分类中封装一个类方法,为了使用更便捷,在做本地化存储的时候,直接将皮肤的标识isNight传递过来,这样就不再需要引用外界的全局变量了,直接在分类中声明一个内部的静态全局部变量标识就可以了
static bool isNight;
+ (void)saveSkinWithNight:(BOOL)night{
// 赋值
isNight = night;
// 保存当前选择的皮肤
[[NSUserDefaults standardUserDefaults]setBool:night forKey:@"night"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
在切换皮肤的时候,调用saveSkinWithNight方法,应用启动的时候,获取标识(应用启动的时候获取一次就可以了,所以在Load方法中获取偏好设置中的数据)
// 程序一起动就会执行(只运行一次)
+ (void)load{
isNight = [[NSUserDefaults standardUserDefaults] boolForKey:@"night"];
}
在ViewController中还需要同步Switch开关的状态(设置夜间后,退出程序再打开,夜间模式图片状态保存成功,但是开关仍然关闭状态),所以在UIImage分类中提供一个类方法,将内部局部变量isNight标识的结果返回给Switch开关所在的控制器
+ (BOOL)isNight{
return isNight;
}
Switch所在控制器中,在ViewDidLoad中设置Switch状态
// 默认关闭 日间模式
self.nightSwitch.on = [UIImage isNight];
完整示例代码
UIImage+JSImage.h:
.h
@interface UIImage (JSImage)
// 根据当前的皮肤设置图片
+ (UIImage *)JSImageNamed:(NSString *)name;
// 保存皮肤
+ (void)saveSkinWithNight:(BOOL)night;
// 获取当前的皮肤情况,Switch开关状态同步显示
+ (BOOL)isNight;
@end
.m
@implementation UIImage (JSImage)
// 引用全局变量
//extern bool isNight; 标识通过封装的saveSkinWithNight方法传递,不再需要引用外界全局变量,所以设置一个静态全局变量即可
static bool isNight;
// 程序一起动就会执行(只运行一次)
+ (void)load{
isNight = [[NSUserDefaults standardUserDefaults] boolForKey:@"night"];
}
+ (UIImage *)JSImageNamed:(NSString *)name{
// 判断当前的皮肤
if (isNight) { // 夜间
// 夜间图片命名:日间+_night
name = [NSString stringWithFormat:@"%@_night",name];
}
return [UIImage imageNamed:name];
}
+ (void)saveSkinWithNight:(BOOL)night{
// 赋值
isNight = night;
// 保存当前选择的皮肤
[[NSUserDefaults standardUserDefaults]setBool:night forKey:@"night"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
+ (BOOL)isNight{
return isNight;
}
@end
Page1控制器:
#import "ViewController.h"
#import "UIImage+JSImage.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView_1;
@property (weak, nonatomic) IBOutlet UIImageView *imageView_2;
@property (weak, nonatomic) IBOutlet UISwitch *nightSwitch;
@end
@implementation ViewController
// 声明全局变量
//bool isNight;
// 切换夜间模式
- (IBAction)clickNightSwitch:(UISwitch *)sender {
// 保存皮肤
[UIImage saveSkinWithNight:sender.isOn];
// 赋值 通过封装的方法已经将标识传递,所以不再需要使用全局变量了
// isNight = sender.isOn;
// if (sender.isOn) { // switch开启,代表夜间模式
// self.imageView_1.image = [UIImage imageNamed:@"baby_night"];
// self.imageView_2.image = [UIImage imageNamed:@"girl_night"];
// } else {
// self.imageView_1.image = [UIImage imageNamed:@"baby"];
// self.imageView_2.image = [UIImage imageNamed:@"girl"];
// }
// 因为判断已经放在了UIImage分类中,所以这里不再需要判断
self.imageView_1.image = [UIImage JSImageNamed:@"baby"];
self.imageView_2.image = [UIImage JSImageNamed:@"girl"];
}
- (void)viewDidLoad {
[super viewDidLoad];
// 默认关闭 日间模式
self.nightSwitch.on = [UIImage isNight];
// self.imageView_1.image = [UIImage imageNamed:@"baby"];
// self.imageView_2.image = [UIImage imageNamed:@"girl"];
self.imageView_1.image = [UIImage JSImageNamed:@"baby"];
self.imageView_2.image = [UIImage JSImageNamed:@"girl"];
}
@end
Page2控制器:
#import "NewViewController.h"
#import "UIImage+JSImage.h"
@interface NewViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageVIew_3;
@end
@implementation NewViewController
- (void)viewDidLoad {
[super viewDidLoad];
// self.imageVIew_3.image = [UIImage imageNamed:@"girl"];
}
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
self.imageVIew_3.image = [UIImage JSImageNamed:@"girl"];
}
@end