一個APP開發(fā)都尾聲時候烙博,老板一句說這字體好小,做一個切換字體的功能吧烟逊!例如QQ微信那樣的渣窜。我當(dāng)時就想這應(yīng)該是用個全局宏定義,就可以吧宪躯!最后發(fā)現(xiàn)乔宿,我的工程項目是用storyboard來創(chuàng)建的,所以沒有例如手寫代碼有一個宏定義的字體定義访雪。全工程都由Xib創(chuàng)建详瑞,IB上修改和設(shè)置字體。瞬間懵逼了臣缀。
不過如果使用宏定義坝橡,我猜想也是不可以的,因為你修改了宏精置,頁面的字體也不會因為宏的改變而去變化计寇。修改了宏并不會去觸發(fā)頁面刷新,需要用全局定義宏,可能需要一個觸發(fā)頁面刷新的方法番宁。也就需要用到通知或者別的元莫。
runTime控制字體
我在網(wǎng)上百度了許久,也去翻墻使用google來搜索一些外文網(wǎng)頁蝶押。只有看到一些類似的踱蠢,主題更換資料。有一個博主有寫了一個方法棋电,使用runTime(運行時)來控制APP程序中的字體變化朽基。寫一個UILabel的分類,在分類用使用+ (void)load { }使用class_getInstanceMethod(Class cls, SEL name)方法獲取自定義方法和系統(tǒng)方法离陶,在使用method_exchangeImplementations(Method m1, Method m2)方法替換系統(tǒng)的方法稼虎。
以下是這方法的代碼:
+ (void)load {
Method imp = class_getInstanceMethod([self class], @selector(initWithCoder:));
Method myImp = class_getInstanceMethod([self class], @selector(myInitWithCoder:));
method_exchangeImplementations(imp, myImp);
}
- (id)myInitWithCoder:(NSCoder*)aDecode {
[self myInitWithCoder:aDecode];
if (self) {
//使用UD獲取本地保存的字體大小
NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
NSNumber *num = [userDefault objectForKey:@"Font"];
CGFloat fontSize = self.font.pointSize;
self.font = [UIFont systemFontOfSize:fontSize + [num floatValue]];
}
return self;
}
只要寫好這個分類,只需要丟入工程內(nèi)就可以直接實現(xiàn)APP的字體變化招刨,方便快捷霎俩。不過這方法有個弊端,就是修改字體后沉眶,需要重新啟動APP打却,才能實現(xiàn)。本人對于APP的內(nèi)存管理知識不是很全面谎倔,大概理解是當(dāng)APP頁面將要出現(xiàn)的時候都會運行+ (void)load { }方法柳击,不過當(dāng)頁面已經(jīng)出現(xiàn)內(nèi)存已經(jīng)存在時候就不會運行+ (void)load { }方法(也可以自己去百度下這方法)如果有大神懂這里面的原由,可以方便告知我下片习。
控制器基類-遍歷
之后我使用基類UIViewController 讓每個基于控制器頁面都繼承于這個類捌肴,就是所謂的基類。然后再這基類中接收一個通知KVO藕咏,觸發(fā)方法來循環(huán)遍歷頁面中所有view.subviews
判斷是否為UIButton和UILabel状知。以下為代碼:
@interface BaseViewController ()
@end
@implementation BaseViewController
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(tongzhi:) name:@"tongzhi" object:nil];
}
- (void)tongzhi:(NSNotification *)text{
NSLog(@"%@",text.userInfo[@"font"]);
NSLog(@"-----接收到通知------");
NSNumber *num = text.userInfo[@"font"];
[self setFont:[num floatValue] forView:self.view];
}
- (void)setFont:(CGFloat)fontSize forView:(UIView*)view{
if ([view isKindOfClass:[UILabel class]]) {
UILabel *lbl = (UILabel *)view;
CGFloat font = lbl.font.pointSize;
lbl.font = [UIFont systemFontOfSize:font + fontSize];
}
if ([view isKindOfClass:[UIButton class]]) {
UIButton *btn = (UIButton *)view;
CGFloat font = btn.titleLabel.font.pointSize;
btn.titleLabel.font = [UIFont systemFontOfSize:font + fontSize];
}
for (UIView *sview in view.subviews) {
[self setFont:fontSize forView:sview];
}
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"tongzhi" object:nil];
}
此方法可以實現(xiàn)字體的改變,不過略微復(fù)雜孽查,因為是每個子類都循環(huán)遍歷饥悴,可能會有系統(tǒng)運行速度過慢等問題。還有因為我的是工程全部使用 storyboard 來搭建的頁面盲再,其中我也使用了UITableViewController西设,雖然UITableViewController也是繼承于UIViewController,就可能需要使用多繼承答朋,Objective-C又不支持多繼承贷揽,需要用協(xié)議來實現(xiàn),感覺有些麻煩绿映,也許是因為本人知識不夠擒滑。所以沒有繼續(xù)下去
設(shè)計思路:控件基類-通知-基類獲取通知
第三種腐晾,也是我現(xiàn)在使用的一種。這種方法就比前面說的簡單丐一,并且不會出現(xiàn)問題藻糖。這是求教了我以前的老大,也根據(jù)網(wǎng)上一些類似的功能库车,主題切換巨柒,來實現(xiàn)的。
首先柠衍,我創(chuàng)建一個繼承于UILabel的基類洋满,在這基類中添加通知KVO,監(jiān)聽字體珍坊。
核心代碼:
@interface BaseLabel ()
@property (assign, nonatomic) CGFloat fontSize;
@end
@implementation BaseLabel
- (id)init {
self = [super init];
if (self != nil) {
NSLog(@"我出現(xiàn)了 init ");
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self != nil) {
NSLog(@"我出現(xiàn)了 initWithCoder");
}
return self;
}
- (void)awakeFromNib {
[super awakeFromNib];
NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
NSNumber *num = [userDefault objectForKey:@"Font"];
CGFloat font = self.font.pointSize;
self.font = [UIFont systemFontOfSize:font + [num floatValue]];
self.fontSize = font;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(fontNotification:) name:@"tongzhi" object:nil];
NSLog(@"我出現(xiàn)了 awakeFromNib %f",self.fontSize);
}
#pragma mark - NSNotification Actions
- (void)fontNotification:(NSNotification *)notification {
NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
NSNumber *num = [userDefault objectForKey:@"Font"];
self.font = [UIFont systemFontOfSize:self.fontSize + [num floatValue]];
}
#pragma mark - Memery Manager
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"tongzhi" object:nil];
}
只需要將工程中的UILabel基于此類就可以牺勾,直接實現(xiàn)字體的變化。使用一些空間約束來調(diào)整因為字體變化的原因而照成的控件變化問題阵漏。(例如tableViewCell高度的變化驻民,需要重新計算÷那樱可以直接使用Label的基類中的通知放到控制器上回还,來監(jiān)聽變化,實現(xiàn)cell高度的動態(tài)變化)
UIButton也可以使用此方法來控制字體的變化叹洲。
最后注意一點柠硕,我們修改APP字體的時候,我們需要保存在標(biāo)準(zhǔn)字號和修改后字體之間的差值运提,我設(shè)置了一個標(biāo)準(zhǔn)字號14蝗柔,因為APP中有這不同的Label字體。
這是工程在GitHub上的地址:changeLabelFont