IBInspectable / IBDesignable可视化控件编程讲解/使用/封装
博客专区 > 冰泪_ 的博客 > 博客详情
IBInspectable / IBDesignable可视化控件编程讲解/使用/封装
冰泪_ 发表于1年前
IBInspectable / IBDesignable可视化控件编程讲解/使用/封装
  • 发表于 1年前
  • 阅读 1091
  • 收藏 13
  • 点赞 2
  • 评论 0

腾讯云 十分钟定制你的第一个小程序>>>   

摘要: IBInspectable / IBDesignable可视化控件编程讲解/使用/封装

前言:

在以前我们使用xib,SB,nib 设置一个view的圆角 边框需要通过一下界面非常的繁琐,所以一般情况下更倾向于使用代码来设置反而更加简单

014.png

在现在 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文件

#import <UIKit/UIKit.h>
IBInspectable
@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.
//

#import <UIKit/UIKit.h>
IBInspectable
@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 <objc/runtime.h>

@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 @end
IB_DESIGNABLE
@implementation __UIView @end


@interface __UILabel : UILabel @end
IB_DESIGNABLE
@implementation __UILabel @end

@interface __UIButton : UIButton @end
IB_DESIGNABLE
@implementation __UIButton @end

@interface __UIImageView : UIImageView @end
IB_DESIGNABLE
@implementation __UIImageView @end

@interface __UITextField : UITextField @end
IB_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  http://git.oschina.net/zhfeiyue/CustomView1

 

 


转载请注明出处谢谢:http://my.oschina.net/iceTear/blog/679949

感觉写的不错的话可以关注我哦

 

 

共有 人打赏支持
粉丝 13
博文 49
码字总数 26720
评论 (0)
×
冰泪_
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: