如何让自定义 UIView 支持 XIB

当我们拖拽一个 view 到 XIB 上,然后设置 view 属性的时候有没有想到让自己定义的 view 也支持通过 XIB 设置属性,甚至还能实时渲染。

过去相关接口是不开放的,但是从 XCode6 开始,我们也可以定义像系统控件一样支持在 XIB 视图下设置属性并能实时渲染的控件了。

@IBInspectable XIB 设置属性

在属性前加上 IBInspectable,就可以再 XIB 中设置这个属性的值了。

@interface UIView (CornerRadius)
@property (nonatomic)IBInspectable CGFloat cornerRadius;
@end

@implementation UIView (CornerRadius)
- (void)setCornerRadius:(CGFloat)cornerRadius{
self.layer.cornerRadius = cornerRadius;
}

- (CGFloat)cornerRadius{
return self.layer.cornerRadius;
}
@end

如何让自定义 UIView 支持 XIB-1

@IBDesignable XIB 实时渲染

只需要在类前加上 IB_DESIGNABLE 即表示该类支持实时渲染

IB_DESIGNABLE
@interface MyView : UIView
@property (nonatomic)IBInspectable CGFloat cornerRadius;
@property (nonatomic)IBInspectable CGFloat borderWidth;
@property (nonatomic)IBInspectable UIColor *borderColor;

@property (nonatomic)IBInspectable NSString *text;
@property (nonatomic)IBInspectable UIColor *textColor;
@property (nonatomic)IBInspectable NSUInteger textSize;// 这里使用 textSize 是因为 IBInspectable 暂时还不支持 UIFont
@end

@implementation MyView
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
// Drawing code
UIFont *font = [UIFont systemFontOfSize:_textSize];
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
style.alignment = NSTextAlignmentCenter;
NSDictionary *dict = @{NSFontAttributeName:font,
NSForegroundColorAttributeName:_textColor,
NSParagraphStyleAttributeName:style};

CGRect contextRect = self.bounds;
CGSize size = [_text sizeWithAttributes:dict];
float x_pos = (contextRect.size.width - size.width) / 2;
float y_pos = (contextRect.size.height - size.height) /2;
[_text drawAtPoint:CGPointMake(self.bounds.origin.x + x_pos, self.bounds.origin.y + y_pos) withAttributes:dict];
}

- (void)setCornerRadius:(CGFloat)cornerRadius{
_cornerRadius = cornerRadius;
self.layer.cornerRadius = cornerRadius;
}

- (void)setBorderWidth:(CGFloat)borderWidth{
_borderWidth = borderWidth;
self.layer.borderWidth = borderWidth;
}

- (void)setBorderColor:(UIColor *)borderColor{
_borderColor = borderColor;
self.layer.borderColor = borderColor.CGColor;
}
@end

如何让自定义 UIView 支持 XIB-2

让 XIB 实时渲染的方式有很多,可以直接重写 setter 方法,在 setter 里面设置实时渲染;另一个是可以重写 prepareForInterfaceBuilder 方法,该方法只在用于 XIB 渲染的时候调用;另外还可以重写 drawRect: 方法。

  • prepareForInterfaceBuilder():此方法与你代码的其余部分一起编译,但只有当视图正在准备在 Interface Builder 显示时执行。
  • TARGET_INTERFACE_BUILDER:#if TARGET_INTERFACE_BUILDER 预处理宏在 Objective-C 或 Swift 下都是工作的,它会视情况编译正确代码:
#if !TARGET_INTERFACE_BUILDER
// this code will run in the app itself
#else
// this code will execute only in IB
#endif

参考

IBInspectable / IBDesignable
Creating a Custom View That Renders in Interface Builder
How to make awesome UI components in iOS 8 using Swift and XCode 6