對iOS中Storyboard的控件進(jìn)行功能性擴(kuò)展方案
一太抓、前言:
Storyboard能夠讓我們對UI界面進(jìn)行快速的搭建,并利用AutoLayout進(jìn)行屏幕的適配罪塔,它能極大的節(jié)省我們的開發(fā)時(shí)間漓摩,同時(shí)以便我們能夠在代碼中完全專注于核心功能的實(shí)現(xiàn)上。
但是膊爪,對于有多語言需求的項(xiàng)目工程自阱,Storyboard的一般做法是:
1、對新增的國際化語言配置文件中進(jìn)行重新的翻譯處理米酬。
2沛豌、把Storyboard中的控件拉到代碼中去重新賦值。
這兩種實(shí)現(xiàn)方式赃额,在處理起來都讓人感到比較惡心加派。當(dāng)然也有人說可以通過腳本來進(jìn)行處理,但實(shí)現(xiàn)的效果可能并不是那么理想跳芳。
在這里芍锦,我們提出了另一種解決方案,就是通過編寫對應(yīng)控件的Category飞盆,讓其在Storyboard上進(jìn)行功能性擴(kuò)展娄琉。
二、IBInspectable關(guān)鍵字:
在此之前桨啃,我們要先介紹一個(gè)關(guān)鍵字——IBInspectable车胡。
在NIB、XIB照瘾、Storyboard的identifier inspector中匈棘,我們可以在User Defined Runtime Attributes對選中的控件進(jìn)行key-value coded,雖然功能強(qiáng)大析命,但一個(gè)屬性的關(guān)鍵字路徑主卫,類型和屬性值需要在每個(gè)實(shí)例設(shè)置,沒有任何自動(dòng)完成或輸入提示鹃愤,這使得工作很繁瑣簇搅。而 IBInspectable 屬性徹底的解決了這個(gè)問題:在 Xcode 6,你現(xiàn)在可以指定任何屬性作為可檢查項(xiàng)并為你的自定義類建立了一個(gè)用戶界面软吐。
比如:當(dāng)我們用IBInspectable去修飾一個(gè)控件的某個(gè)屬性時(shí)瘩将,Storyboard對應(yīng)控件的Attributes inspector中將會(huì)多出該屬性的選項(xiàng)。當(dāng)我們對該選項(xiàng)進(jìn)行修改賦值時(shí),identifier inspector中的key-value coded就會(huì)相應(yīng)的做出變化姿现。
三肠仪、對Storyboard的控件進(jìn)行多語言功能擴(kuò)展:
這里,我們拿UILabel作為示例备典,當(dāng)然异旧,UIButton和UITextField等的文本多語言設(shè)計(jì)思路也是一樣的:
- 1、通過Category對UILabel添加一個(gè)BOOL值的屬性擴(kuò)展提佣。
- 2吮蛹、用IBInspectable關(guān)鍵字對這個(gè)屬性進(jìn)行修飾,使得我們能夠在Storyboard中對其進(jìn)行修改拌屏。
- 3潮针、當(dāng)我們在Storyboard中對該屬性設(shè)為true時(shí),我們希望UILabel的text能夠作為多語言實(shí)現(xiàn)方法NSLocalizedString(key, comment)中的key槐壳,從而對UILabel的text重新賦值然低。
這樣一來,我們只需要在Localizable.strings文件中對文案進(jìn)行鍵值對編寫便可實(shí)現(xiàn)本地化务唐,無需再把控件拖進(jìn)代碼中去修改了雳攘,也不用新增國際化語言配置文件中去重新翻譯了。具體實(shí)現(xiàn)代碼如下:
UILabel+SBLocalizable.h中:
#import <UIKit/UIKit.h>
@interface UILabel (SBLocalizable)
/**
是否把當(dāng)前text作為多語言的key
*/
@property (nonatomic, assign) IBInspectable BOOL textAsKey;
@end
UILabel+SBLocalizable.m中:
#import "UILabel+SBLocalizable.h"
#import <objc/runtime.h>
static const void *kLabelTextKey = &kLabelTextKey;
@implementation UILabel (SBLocalizable)
- (BOOL)textAsKey {
return [objc_getAssociatedObject(self, @selector(textAsKey)) boolValue];
}
- (void)setTextAsKey:(BOOL)textAsKey {
objc_setAssociatedObject(self,
@selector(textAsKey),
@(textAsKey),
OBJC_ASSOCIATION_ASSIGN);
if (textAsKey) {
objc_setAssociatedObject(self,
kLabelTextKey,
self.text,
OBJC_ASSOCIATION_COPY_NONATOMIC);
self.text = NSLocalizedString(self.text, nil);
} else {
self.text = objc_getAssociatedObject(self, kLabelTextKey);
}
}
@end
四枫笛、對Storyboard的控件進(jìn)行顏色功能擴(kuò)展:
看了上面對多語言功能的擴(kuò)展吨灭,我們可以用類型的方法,對控件添加一個(gè)UIColor的屬性刑巧,并用IBInspectable關(guān)鍵字對其進(jìn)行修飾喧兄,這樣便可在Storyboard上對該屬性的顏色進(jìn)行修改了。
但是啊楚,一旦設(shè)計(jì)師要求對顏色進(jìn)行調(diào)整吠冤,那么,我們便要一個(gè)個(gè)的去把相應(yīng)的控件找出來恭理,重新給顏色賦值拯辙,這又是一個(gè)惡心的任務(wù)。于是我們提供了另一種設(shè)計(jì)思路颜价,這里用UIView作為示例:
- 1涯保、新建一個(gè)UIColor的Category,并用類方法返回我們需要的顏色周伦。
- 2夕春、通過Category對UIVIew添加一個(gè)字符串屬性擴(kuò)展,這里我們就命名為bgColorName吧专挪。
- 3及志、用IBInspectable關(guān)鍵字對這個(gè)屬性進(jìn)行修飾片排,使得我們能夠在Storyboard中對其進(jìn)行修改。
- 4速侈、在Storyboard中UIView控件的新屬性上划纽,我們填寫剛才新建的UIColor的取得顏色的類方法名。
- 5锌畸、在bgColorName的set方法中,我們把取得的字符串轉(zhuǎn)為UIColor的類方法靖避,并取得對應(yīng)的顏色潭枣,從而給UIView的backgroundColor重新賦值。
這樣一來幻捏,一旦我們要替換某個(gè)顏色時(shí)盆犁,只要進(jìn)行全局搜索,并讓Storyboard以Source code的方式打開篡九,便可以進(jìn)行全局替換谐岁。具體實(shí)現(xiàn)代碼如下:
? UIColor+CorosColor.h中:
#import <UIKit/UIKit.h>
@interface UIColor (CorosColor)
+ (UIColor *)clearClr;
+ (UIColor *)whiteClr;
+ (UIColor *)blackClr;
+ (UIColor *)blueClr;
+ (UIColor *)redClr;
@end
? UIView+BackgroundColor.h中:
#import <UIKit/UIKit.h>
@interface UIView (BackgroundColor)
/**
背景顏色名稱
*/
@property (nullable, nonatomic, strong) IBInspectable NSString *bgColorName;
@end
UIView+BackgroundColor.m中:
#import "UIView+BackgroundColor.h"
#import <objc/runtime.h>
@implementation UIView (BackgroundColor)
- (nullable NSString *)bgColorName {
return objc_getAssociatedObject(self, @selector(bgColorName));
}
- (void)setBgColorName:(NSString *)bgColorName {
if (!bgColorName || bgColorName.length == 0) {
return;
}
UIColor *color;
SEL sel = NSSelectorFromString(bgColorName);
if ([UIColor respondsToSelector:sel]) {
color = [UIColor performSelector:sel];
}
if (!color) {
return;
}
self.backgroundColor = color;
objc_setAssociatedObject(self,
@selector(bgColorName),
bgColorName,
OBJC_ASSOCIATION_COPY_NONATOMIC);
}
@end
五、結(jié)束語:
通過以上對IBInspectable的使用和設(shè)計(jì)思路榛臼,我們就可以根據(jù)需要伊佃,對相應(yīng)的控件在Storyboard中進(jìn)行功能性擴(kuò)展,從而更好的利用Storyboard在UI搭建上的便利性沛善,使得我們能在更簡潔的代碼中去專注于核心功能的實(shí)現(xiàn)上(PS:大家有空可以看看另一個(gè)相當(dāng)有意思的關(guān)鍵字——IB_DESIGNABLE)航揉。
最后需要注意的地方是,當(dāng)我們不想使用該Category擴(kuò)展出來的功能時(shí)金刁,僅僅是刪去Category代碼文件是不夠帅涂,因?yàn)楫?dāng)你在Storyboard中對相應(yīng)控件的新增屬性進(jìn)行了更改賦值后,identifier inspector中的key-value coded并不會(huì)自動(dòng)去刪除對應(yīng)的屬性尤蛮,這里我們還需要手動(dòng)去刪除對應(yīng)的編碼值媳友。或者我們在刪除Category代碼文件前产捞,先將Storyboard中控件對應(yīng)的屬性改回默認(rèn)值Default醇锚,然后再刪除Category代碼文件。