前言:
在以前我们使用xib,SB,nib 设置一个view的圆角 边框需要通过一下界面非常的繁琐,所以一般情况下更倾向于使用代码来设置反而更加简单
在现在 IBInspectable 属性彻底的解决了这个问题:在 Xcode 6,你现在可以指定任何属性作为可检查项 来设置对应的属性
正题:
一、iOS8新特性IBDesignable(swift)/IBInspectable(oc),可以直接在XIB或者Storyboard中直接,设置UI类的属性。
例如:UIView.layer.borderWidth、borderColor、cornerRadius这些属性在XIB上是不能直接设置的,但是 IBDesignable/IBInspectable,利用runtime机制,就可以把这些属性映射到XIB上了,同时我们UI类的自定义属性也可以映射上 去。
二、IB_DESIGNABLE 的具体使用方法:
IB_DESIGNABLE
的宏
的功能就是让XCode动态渲染
出该类图形化界面;
使用IB_DESIGNABLE
的方式,把该宏加在自定义类的前面;
当然还需要设置下xib的动态刷新要不然可能无法实时显示 具体设置见下图
三、下边附上自定义的demo代码 里边简单的实现了边框和 圆角的可视化修改
使用时候可以需将 view对应的class 改为customView
//CustomView.h文件#importIBInspectable@interface CustomView : UIView@property (nonatomic, assign)IBInspectable CGFloat cornerRadius;@property (nonatomic, assign)IBInspectable CGFloat BoderWidth;@property (nonatomic, assign)IBInspectable UIColor *BoderColor;@end//CustomView.m文件#import "CustomView.h"IB_DESIGNABLE@implementation CustomView- (void)setCornerRadius:(CGFloat)cornerRadius{ _cornerRadius = cornerRadius; self.layer.cornerRadius = _cornerRadius;}-(void)setBoderColor:(UIColor *)BoderColor{ _BoderColor = BoderColor; self.layer.borderColor = _BoderColor.CGColor;}-(void)setBoderWidth:(CGFloat)BoderWidth{ _BoderWidth = BoderWidth; self.layer.borderWidth = _BoderWidth; }@end
四、IBInspectable / IBDesignable封装(导入项目之后可以对UIView 、UILabel、UIButton、UIImageView、UITextField使用)
首先代码部分
//// UIView+LCUtils.h// iceTearsTest//// Created by 冰泪 on 16/5/19.// Copyright © 2016年 冰泪. All rights reserved.//#importIBInspectable@interface CustomView : UIView@property (nonatomic, assign)IBInspectable CGFloat cornerRadius;@property (nonatomic, assign)IBInspectable CGFloat BoderWidth;@property (nonatomic, assign)IBInspectable UIColor *BoderColor;@end//// UIView+LCUtils.m// iceTearsTest//// Created by 冰泪 on 16/5/19.// Copyright © 2016年 冰泪. All rights reserved.//#import "UIView+LCUtils.h"#import @interface LCEdgeLayer : CALayer@property(nonatomic) UIEdgeInsets edges;@property(nonatomic) UIColor *leftColor;@property(nonatomic) UIColor *topColor;@property(nonatomic) UIColor *rightColor;@property(nonatomic) UIColor *bottomColor;@property(nonatomic) BOOL widthUnitInPixel;@end@implementation LCEdgeLayer- (void)setLeftColor:(UIColor *)leftColor { _leftColor = leftColor; [self setNeedsDisplay];}- (void)setRightColor:(UIColor *)rightColor { _rightColor = rightColor; [self setNeedsDisplay];}- (void)setTopColor:(UIColor *)topColor { _topColor = topColor; [self setNeedsDisplay];}- (void)setBottomColor:(UIColor *)bottomColor { _bottomColor = bottomColor; [self setNeedsDisplay];}- (void)setEdges:(UIEdgeInsets)edges { _edges = edges; [self setNeedsDisplay];}-(void)setWidthUnitInPixel:(BOOL)widthUnitInPixel{ _widthUnitInPixel = widthUnitInPixel; [self setNeedsDisplay];}- (void)drawInContext:(CGContextRef)ctx { const CGFloat ONE_PIXEL_WIDTH = 1.0 / self.contentsScale; if (_edges.left > 0 && _leftColor) { CGContextSetFillColorWithColor(ctx, _leftColor.CGColor); CGRect rect = self.bounds; if (_widthUnitInPixel) rect.size.width = _edges.left * ONE_PIXEL_WIDTH; else rect.size.width = _edges.left; CGContextFillRect(ctx, rect); } if (_edges.top > 0 && _topColor) { CGContextSetFillColorWithColor(ctx, _topColor.CGColor); CGRect rect = self.bounds; if (_widthUnitInPixel) rect.size.height = _edges.top * ONE_PIXEL_WIDTH; else rect.size.height = _edges.top; CGContextFillRect(ctx, rect); } if (_edges.right > 0 && _rightColor) { CGContextSetFillColorWithColor(ctx, _rightColor.CGColor); CGRect rect = self.bounds; if (_widthUnitInPixel){ rect.origin.x += (rect.size.width - _edges.right * ONE_PIXEL_WIDTH); rect.size.width = _edges.right * ONE_PIXEL_WIDTH; } else{ rect.origin.x += (rect.size.width - _edges.right); rect.size.width = _edges.right; } CGContextFillRect(ctx, rect); } if (_edges.bottom > 0 && _bottomColor) { CGContextSetFillColorWithColor(ctx, _bottomColor.CGColor); CGRect rect = self.bounds; if (_widthUnitInPixel){ rect.origin.y += (rect.size.height - _edges.bottom * ONE_PIXEL_WIDTH); rect.size.height = _edges.bottom * ONE_PIXEL_WIDTH; } else{ rect.origin.y += (rect.size.height - _edges.bottom); rect.size.height = _edges.bottom; } CGContextFillRect(ctx, rect); }}@end@interface CALayer (Edge)-(LCEdgeLayer*) lc_findEdgeLayer;-(LCEdgeLayer*) lc_ensureEdgeLayer;@end@implementation CALayer (Hook)#if !TARGET_INTERFACE_BUILDER+ (void)load { Method m1 = class_getInstanceMethod(self, @selector(lc_layoutSublayers)); Method m2 = class_getInstanceMethod(self, @selector(layoutSublayers)); method_exchangeImplementations(m1, m2);}- (void)lc_layoutSublayers { [self lc_layoutSublayers]; [self lc_findEdgeLayer].frame = self.bounds;}#endif-(LCEdgeLayer*) lc_findEdgeLayer { for (CALayer *layer in self.sublayers) { if ([layer isKindOfClass:LCEdgeLayer.class]) { return (LCEdgeLayer*)layer; } } return nil;}-(LCEdgeLayer*) lc_ensureEdgeLayer{ return [self lc_findEdgeLayer] ?: ({ LCEdgeLayer * edgeLayer = [LCEdgeLayer layer]; edgeLayer.contentsScale = [UIScreen mainScreen].scale;; edgeLayer.frame = self.bounds; edgeLayer.needsDisplayOnBoundsChange = YES; [self insertSublayer:edgeLayer atIndex:0]; edgeLayer; });}@end@implementation UIView (Edge)#pragma -mark WIDTH- (CGFloat)edgeWidthLeft_lc{ return [self.layer lc_findEdgeLayer].edges.left;}-(void)setEdgeWidthLeft_lc:(CGFloat)edgeWidthLeft_lc{ LCEdgeLayer * layer = [self.layer lc_ensureEdgeLayer]; UIEdgeInsets edges = layer.edges; edges.left = edgeWidthLeft_lc; layer.edges = edges;}- (CGFloat)edgeWidthRight_lc{ return [self.layer lc_findEdgeLayer].edges.right;}-(void)setEdgeWidthRight_lc:(CGFloat)edgeWidthRight_lc{ LCEdgeLayer * layer = [self.layer lc_ensureEdgeLayer]; UIEdgeInsets edges = layer.edges; edges.right = edgeWidthRight_lc; layer.edges = edges;}- (CGFloat)edgeWidthTop_lc{ return [self.layer lc_findEdgeLayer].edges.top;}-(void)setEdgeWidthTop_lc:(CGFloat)edgeWidthTop_lc{ LCEdgeLayer * layer = [self.layer lc_ensureEdgeLayer]; UIEdgeInsets edges = layer.edges; edges.top = edgeWidthTop_lc; layer.edges = edges;}- (CGFloat)edgeWidthBottom_lc{ return [self.layer lc_findEdgeLayer].edges.bottom;}-(void)setEdgeWidthBottom_lc:(CGFloat)edgeWidthBottom_lc{ LCEdgeLayer * layer = [self.layer lc_ensureEdgeLayer]; UIEdgeInsets edges = layer.edges; edges.bottom = edgeWidthBottom_lc; layer.edges = edges;}- (BOOL)edgeWidthUnitInPixel_lc{ return [self.layer lc_findEdgeLayer].widthUnitInPixel;}-(void)setEdgeWidthUnitInPixel_lc:(BOOL)edgeWidthUnitInPixel_lc{ [self.layer lc_ensureEdgeLayer].widthUnitInPixel = edgeWidthUnitInPixel_lc;}- (CGFloat)edgeZPosition_lc{ return [self.layer lc_findEdgeLayer].zPosition;}-(void)setEdgeZPosition_lc:(CGFloat)edgeZPosition_lc{ LCEdgeLayer * layer = [self.layer lc_ensureEdgeLayer]; layer.zPosition = edgeZPosition_lc;#if TARGET_INTERFACE_BUILDER [layer removeFromSuperlayer]; for(CALayer * sub in self.layer.sublayers){ if(edgeZPosition_lc <= sub.zPosition){ [self.layer insertSublayer:layer below:sub]; break; } } if(!layer.superlayer) [self.layer addSublayer:layer]; #endif }#pragma -mark COLOR-(UIColor *)edgeColorLeft_lc{ return [self.layer lc_findEdgeLayer].leftColor;}-(void)setEdgeColorLeft_lc:(UIColor *)edgeColorLeft_lc{ [self.layer lc_ensureEdgeLayer].leftColor = edgeColorLeft_lc;}-(UIColor *)edgeColorRight_lc{ return [self.layer lc_findEdgeLayer].rightColor;}-(void)setEdgeColorRight_lc:(UIColor *)edgeColorRight_lc{ [self.layer lc_ensureEdgeLayer].rightColor = edgeColorRight_lc;}-(UIColor *)edgeColorTop_lc{ return [self.layer lc_findEdgeLayer].topColor;}-(void)setEdgeColorTop_lc:(UIColor *)edgeColorTop_lc{ [self.layer lc_ensureEdgeLayer].topColor = edgeColorTop_lc;}-(UIColor *)edgeColorBottom_lc{ return [self.layer lc_findEdgeLayer].bottomColor;}-(void)setEdgeColorBottom_lc:(UIColor *)edgeColorBottom_lc{ [self.layer lc_ensureEdgeLayer].bottomColor = edgeColorBottom_lc;}@end@implementation UIView(Border)-(UIColor *)borderColor_lc{ return [UIColor colorWithCGColor:self.layer.borderColor];}-(void)setBorderColor_lc:(UIColor *)borderColor_lc{ self.layer.borderColor = borderColor_lc.CGColor;}-(CGFloat)borderWidth_lc{ return [objc_getAssociatedObject(self, _cmd) floatValue];}-(void)setBorderWidth_lc:(CGFloat)borderWidth_lc{ objc_setAssociatedObject(self, @selector(borderWidth_lc), @(borderWidth_lc), OBJC_ASSOCIATION_RETAIN); if(self.borderWidthUnitInPixel_l) self.layer.borderWidth = borderWidth_lc / [UIScreen mainScreen].scale; else self.layer.borderWidth = borderWidth_lc;}-(BOOL)borderWidthUnitInPixel_l{ return [objc_getAssociatedObject(self, _cmd) boolValue];}-(void)setBorderWidthUnitInPixel_l:(BOOL)borderWidthUnitInPixel_l{ objc_setAssociatedObject(self, @selector(borderWidthUnitInPixel_l), @(borderWidthUnitInPixel_l), OBJC_ASSOCIATION_RETAIN); if(borderWidthUnitInPixel_l) self.layer.borderWidth = self.borderWidth_lc / [UIScreen mainScreen].scale; else self.layer.borderWidth = self.borderWidth_lc; }-(CGFloat)borderCornerRadius_lc{ return self.layer.cornerRadius;}-(void)setBorderCornerRadius_lc:(CGFloat)borderCornerRadius_lc{ self.layer.cornerRadius = borderCornerRadius_lc;}-(UIColor *)borderLayerColor_lc{ return [UIColor colorWithCGColor: self.layer.backgroundColor];}-(void)setBorderLayerColor_lc:(UIColor *)borderLayerColor_lc{ self.layer.backgroundColor = borderLayerColor_lc.CGColor;}-(BOOL)clipsToBounds_lc{ return self.clipsToBounds;}-(void)setClipsToBounds_lc:(BOOL)clipToBounds_lc{ self.clipsToBounds = clipToBounds_lc;}-(UIColor *)shadowColor_lc{ return [UIColor colorWithCGColor:self.layer.shadowColor];}-(void)setShadowColor_lc:(UIColor *)shadowColor_lc{ self.layer.shadowColor = shadowColor_lc.CGColor;}-(CGFloat)shadowOpacity_lc{ return self.layer.shadowOpacity;}-(void)setShadowOpacity_lc:(CGFloat)shadowOpacity_lc{ self.layer.shadowOpacity = shadowOpacity_lc;}-(CGFloat)shadowRadius_lc{ return self.layer.shadowRadius;}-(void)setShadowRadius_lc:(CGFloat)shadowRadius_lc{ self.layer.shadowRadius = shadowRadius_lc;}-(CGPoint)shadowOffset_lc{ CGSize size = self.layer.shadowOffset; return CGPointMake(size.width, size.height);}-(void)setShadowOffset_lc:(CGPoint)shadowOffset_lc{ self.layer.shadowOffset =#if TARGET_INTERFACE_BUILDER CGSizeMake(shadowOffset_lc.x, -shadowOffset_lc.y);#else CGSizeMake(shadowOffset_lc.x, shadowOffset_lc.y);#endif }@end@interface LCLayoutConstraint : NSLayoutConstraint+ (instancetype) constraintOfZeroAttribute:(NSLayoutAttribute) attr toView:(UIView*)view;@end@implementation LCLayoutConstraint+ (instancetype) constraintOfZeroAttribute:(NSLayoutAttribute) attr toView:(UIView*)view{ return [self constraintWithItem:view attribute:attr relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:0];}@end@implementation UIView(Visibility)- (LCLayoutConstraint*) findConstraintByAttribute:(NSLayoutAttribute)attr{ for(NSLayoutConstraint * con in self.constraints){ if([con isKindOfClass:LCLayoutConstraint.class] && con.firstAttribute == attr) return (LCLayoutConstraint*)con; } return nil;}- (LCLayoutConstraint*) ensureConstraintByAttribute:(NSLayoutAttribute)attr{ return [self findConstraintByAttribute:attr] ?:({ LCLayoutConstraint *con = [LCLayoutConstraint constraintOfZeroAttribute:attr toView:self]; [self addConstraint:con]; con; });}- (BOOL)goneHorizontal_lc{ return [self findConstraintByAttribute:NSLayoutAttributeWidth];}-(void)setGoneHorizontal_lc:(BOOL)goneHorizontal_lc{ if(goneHorizontal_lc){ [self ensureConstraintByAttribute:NSLayoutAttributeWidth]; }else{ NSLayoutConstraint * cons = [self findConstraintByAttribute:NSLayoutAttributeWidth]; if(cons) [self removeConstraint:cons]; }}-(BOOL)goneVertical_lc{ return [self findConstraintByAttribute:NSLayoutAttributeHeight];}-(void)setGoneVertical_lc:(BOOL)goneVertical_lc{ if(goneVertical_lc){ [self ensureConstraintByAttribute:NSLayoutAttributeHeight]; }else{ NSLayoutConstraint * cons = [self findConstraintByAttribute:NSLayoutAttributeHeight]; if(cons) [self removeConstraint:cons]; }}@end@implementation UIView(Xib)+ (UIView*) lc_loadXibIntoView:(UIView *)view owner:(UIView *) owner{ NSString * xibName = NSStringFromClass(self); NSBundle * bundle = [NSBundle bundleForClass:self]; UIView * contentView; @try{ contentView = [bundle loadNibNamed:xibName owner:owner options:nil].firstObject; }@catch(NSException * e){#if TARGET_INTERFACE_BUILDER @try{ contentView = [bundle loadNibNamed:[xibName stringByAppendingString:@"~iphone"] owner:owner options:nil].firstObject; }@catch(NSException * e){ contentView = [bundle loadNibNamed:[xibName stringByAppendingString:@"~ipad"] owner:owner options:nil].firstObject; }#else @throw e;#endif } //required if we manually add sub view with constraints contentView.translatesAutoresizingMaskIntoConstraints = NO; [view addSubview:contentView]; [view addConstraint:[NSLayoutConstraint constraintWithItem:contentView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:view attribute:NSLayoutAttributeTop multiplier:1 constant:0]]; [view addConstraint:[NSLayoutConstraint constraintWithItem:contentView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:view attribute:NSLayoutAttributeLeft multiplier:1 constant:0]]; [view addConstraint:[NSLayoutConstraint constraintWithItem:contentView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:view attribute:NSLayoutAttributeRight multiplier:1 constant:0]]; [view addConstraint:[NSLayoutConstraint constraintWithItem:contentView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:view attribute:NSLayoutAttributeBottom multiplier:1 constant:0]]; return contentView; }@end//set custom class to __cls to preview in IB@interface __UIView : UIView @endIB_DESIGNABLE@implementation __UIView @end@interface __UILabel : UILabel @endIB_DESIGNABLE@implementation __UILabel @end@interface __UIButton : UIButton @endIB_DESIGNABLE@implementation __UIButton @end@interface __UIImageView : UIImageView @endIB_DESIGNABLE@implementation __UIImageView @end@interface __UITextField : UITextField @endIB_DESIGNABLE@implementation __UITextField @end
该代码可用于
UIView 、UILabel、UIButton、UIImageView、UITextField
可以设置独立的上、下、左、右、边框,四边的边框, 阴影,圆角
使用时候也非常简单
1、导入UIView+LCUtils.h/UIView+LCUtils.m 文件到项目中
2、只需要把对应的类换成__UIView(前边是两个下划线_) 、__UILabel、__UIButton、__UIImageView、__UITextField 其余地方不用做任何更改 和正常的写法一样即可 通过SB/xib/nib 的可视化面板来进行对边框 /圆角 /阴影的快速设置,能为我们编程节省很多时间
然后在设置里边将出现以下菜单选项 可以设置不同的属性
上边数据显示不是很全可以以代码作为参考 很好明白对应的是什么意思
//左边框 @property(nonatomic) IBInspectable CGFloat edgeWidthLeft_lc; @property(nonatomic) IBInspectable UIColor * edgeColorLeft_lc; //顶边框 @property(nonatomic) IBInspectable CGFloat edgeWidthTop_lc; @property(nonatomic) IBInspectable UIColor * edgeColorTop_lc; //右边框 @property(nonatomic) IBInspectable CGFloat edgeWidthRight_lc; @property(nonatomic) IBInspectable UIColor * edgeColorRight_lc; //下边框 @property(nonatomic) IBInspectable CGFloat edgeWidthBottom_lc; @property(nonatomic) IBInspectable UIColor * edgeColorBottom_lc;
//边框开关 @property(nonatomic) IBInspectable BOOL edgeWidthUnitInPixel_lc;
@property(nonatomic) IBInspectable CGFloat edgeZPosition_lc; @end
@interface UIView(Border) //边框 颜色 宽度 以及是否开启边框 @property(nonatomic) IBInspectable UIColor * borderColor_lc; @property(nonatomic) IBInspectable CGFloat borderWidth_lc; @property(nonatomic) IBInspectable BOOL borderWidthUnitInPixel_l; //圆角 @property(nonatomic) IBInspectable CGFloat borderCornerRadius_lc; @property(nonatomic) IBInspectable UIColor * borderLayerColor_lc; @property(nonatomic) IBInspectable BOOL clipsToBounds_lc; //阴影 @property(nonatomic) IBInspectable UIColor * shadowColor_lc;//shadowColor阴影颜色 @property(nonatomic) IBInspectable CGFloat shadowOpacity_lc;//阴影透明度,默认0 @property(nonatomic) IBInspectable CGFloat shadowRadius_lc;//阴影半径,默认3 @property(nonatomic) IBInspectable CGPoint shadowOffset_lc;//shadowOffset阴影偏移,x向右偏移4,y向下偏移4,默认(0, -3),这个跟shadowRadius配合使 @end
最后附上demo
转载请注明出处谢谢:
感觉写的不错的话可以关注我哦