iOS 好东西iOS

iOS开发——IB控件自定义属性的优化场景

2018-07-20  本文已影响87人  Warl_G

自定义IB属性对统一样式的优化

开发中为保证界面的一致性会使用统一的设计样式,包括字体、颜色等,一旦设计变化会导致整个项目的内容大量的重复性修改,不但浪费时间还不能保证完全覆盖。为此开发者经常会使用统一的配置文件去配置界面样式,通过修改配置文件达到修改一处全局变化的效果。但这样仍然有一点瑕疵,使用代码创建的控件在创建时即可选择界面的样式类型,但xib或storyboard创建的控件仍需要额外的引用并配置,因此我思考能否在Interface Builder中就配置好控件的样式类型。
此文不讨论自定义样式实现方案,仅提供一种Interface Builder自定义属性对于样式配置的一种解决思路

基本思路

查找发现可为属性添加IBInspectable关键字以实现在Interface Builder属性栏添加自定义属性,另外还有一个关键字IBDesignable可实现Interface Builder中的实时渲染,但因本方案使用的是UIView的分类,IBDesignable关键字在分类中无效,所以不做赘述。

实现方法

通过为UIView分类为所有的View控件添加属性styleCode,用于配置控件的样式类型。

@interface UIView (Xib)

@property (nonatomic, assign) IBInspectable NSUInteger styleCode;

@end

因OC的分类中不能直接添加属性,为了方便外部能够查看样式类型使用关联对象将其记录下来,关联对象的知识可另行查阅资料。
因为有四个控件为体现出不同样式但又想偷懒所以仅改变其字体粗细和背景颜色,实际开发中应当为读取样式配置文件分别配置。

static char customStyleCode;

@implementation UIView (Xib)

- (NSUInteger)styleCode {
    return [(NSNumber *)objc_getAssociatedObject(self, &customStyleCode) unsignedIntegerValue];
}

- (void)setStyleCode:(NSUInteger)styleCode {
    objc_setAssociatedObject(self, &customStyleCode, @(styleCode), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    //此处应根据读取配置文件选择样式,仅做演示只修改字体粗细
    if (styleCode == 0) {
        [self setBoldFont:NO];
        self.backgroundColor = [UIColor redColor];
    }else if (styleCode == 1) {
        [self setBoldFont:YES];
        self.backgroundColor = [UIColor blueColor];
    }else if (styleCode == 2) {
        [self setBoldFont:NO];
        self.backgroundColor = [UIColor greenColor];
    }else if (styleCode == 3) {
        [self setBoldFont:YES];
        self.backgroundColor = [UIColor lightGrayColor];
    }
}

//判断View类型、针对不同类型修改字体
- (void)setBoldFont:(BOOL)bold {
    UIFont *font = bold ? [UIFont boldSystemFontOfSize:12] : [UIFont systemFontOfSize:12];
    
    if ([self isMemberOfClass:UILabel.class]) {
        UILabel *label = (UILabel *)self;
        label.font = font;
    }else if ([self isMemberOfClass:UIButton.class]){
        UIButton *button = (UIButton *)self;
        button.titleLabel.font = font;
    }else if ([self isMemberOfClass:UITextField.class]){
        UITextField *textField = (UITextField *)self;
        textField.font = font;
    }else if ([self isMemberOfClass:UITextView.class]){
        UITextView *textView = (UITextView *)self;
        textView.font = font;
    }
}

@end

此处使用isMemberOfClass方法判断View类型是为了对开发者创建的子类仍能起作用

摆放好控件查看右侧属性列表可见

在修改完其数值后可在User Defined Runtime Attributes栏发现多了我们添加的属性,所以对于非Interface Builder可见的属性也可在此处添加后进行配置,如我们常用到的layer.cornerRadius和layer.borderWidth。
运行效果如图

通过追踪生命周期

initWithCoder:
setStyleCode:
awakeFromNib:

可见Interface Builder配置的属性在控件初始化时就已加载完成,若想更改属性只要在awakeFromNib:后修改即可。

自定义IB属性对多语言配置的优化

iOS开发中配置多语言不但要添加全局多语言文件使用键值对的形式配置显示文案,而且每个Xib文件和Stroyboard文件也需要单独添加多语言文件,大大增加了工作的重复性和不确定性。因此通过自定义IB属性用于加载全局多语言文件,免去了为IB文件单独添加多语言的烦恼。
属性添加方式同上

@property (nonatomic, strong) IBInspectable NSString *stringKey;
- (NSString *)stringKey {
    return objc_getAssociatedObject(self, &customStringKey);
}

- (void)setStringKey:(NSString *)stringKey {
    objc_setAssociatedObject(self, &customStringKey, stringKey, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    [self setLocalText:stringKey];
}

- (void)setLocalText:(NSString *)stringKey {
    //此处仅模拟多语言环境,根据英文文案选出中文案
    NSDictionary *localText = @{@"test" : @"测试", @"text" : @"文案"};
    NSString *text = localText[stringKey];
    if ([self isMemberOfClass:UILabel.class]) {
        UILabel *label = (UILabel *)self;
        label.text = text;
    }else if ([self isMemberOfClass:UIButton.class]){
        UIButton *button = (UIButton *)self;
        [button setTitle:text forState:UIControlStateNormal];
    }else if ([self isMemberOfClass:UITextField.class]){
        UITextField *textField = (UITextField *)self;
        textField.text = text;
    }else if ([self isMemberOfClass:UITextView.class]){
        UITextView *textView = (UITextView *)self;
        textView.text = text;
    }
}

配置如图

运行效果

为做样例该方案使用UIView的分类对所有控件统一实现,在实际开发中可根据需求对个别控件单独添加属性,如UITextField控件的placeholder属性,或UIButton的对不同State设置不同Title。

上一篇 下一篇

猜你喜欢

热点阅读