iosobjective-cstoryboardibdesignableibinspectable

extend class with IB_DESIGNABLE obj-c


I found IBDesignable and IBInspectable very usefull to bring setter possibility directly to the storyboard.

I use it in a swift projet that way

import Foundation
import UIKit
@IBDesignable extension UIView {

    @IBInspectable var addBorderTop: CGFloat {
        set {
            addBorderUtility(0, y: 0, width: frame.width, height: newValue, color: layer.borderColor)
        }
        get {
            return 0
        }
    }

    @IBInspectable var addBorderBottom: CGFloat {
        set {
            addBorderUtility(0, y: frame.height - newValue, width: frame.width, height: newValue, color: layer.borderColor)

        }
        get {
            return 0
        }
    }

    @IBInspectable var addBorderLeft: CGFloat {
        set {
            addBorderUtility(0, y: 0, width: newValue, height: frame.height, color: layer.borderColor)
        }
        get {
            return 0
        }
    }

    @IBInspectable var addBorderRight: CGFloat {
        set {
            addBorderUtility(frame.width - newValue, y: 0, width: newValue, height: frame.height, color:  layer.borderColor)
        }
        get {
            return 0
        }
    }

    private func addBorderUtility(_ x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat, color: CGColor?) {
        let border = CALayer()
        border.backgroundColor = color
        border.frame = CGRect(x: x, y: y, width: width, height: height)
        layer.addSublayer(border)
    }
}

this is working like a charms. So I decided to do the same thing on an objective-c project, trying to extend UIView here is hhow it looks like

UIView+Border.h

#import <UIKit/UIKit.h>

@interface UIView ()
@property (nonatomic) IBInspectale CGFloat addBorderTop;
@property (nonatomic) IBInspectale CGFloat addBorderBottom;
@property (nonatomic) IBInspectale CGFloat addBorderLeft;
@property (nonatomic) IBInspectale CGFloat addBorderRight;
@end

UIView+Border.m

#import "UIView+Border.h"

@interface UIView ()

IB_DESIGNABLE
@implementation UIView ()

- (void) setAddBorderTop: (CGFloat) newValue
{
    addBorderUtility(0, y: 0, width: frame.width, height: newValue, color: layer.borderColor)
}

- (void) setAddBorderBottom: (CGFloat) newValue
{
    addBorderUtility(0, y: frame.height - newValue, width: frame.width, height: newValue, color: layer.borderColor)
}

- (void) setAddBorderLeft: (CGFloat) newValue
{
    addBorderUtility(0, y: 0, width: newValue, height: frame.height, color: layer.borderColor)
}

- (void) setAddBorderRight: (CGFloat) newValue
{
    addBorderUtility(frame.width - newValue, y: 0, width: newValue, height: frame.height, color: layer.borderColor)
}

- (void) addBorderUtility: (CGFloat):x y:(CGFloat)y width:(CGFloat)width  height:(CGFloat)height color:(CGColor)color
{
    CALayer *border = [CALayer init]
    border.backgroundColor = color
    border.frame = CGRect(x: x, y: y, width: width, height: height)
    layer.addSublayer(border)
}
@end

but none of my custom variabble are settable from the right menu on the storyboard. I also tried to add an User Defined Runtime Attributes having the same name as one of my custome variable,nothing happened once you run the app.

any idea how to do that ? thanks


Solution

  • There is many mistake in you Objective-C code, I have update it. You have to use CALayer *border = [CALayer layer]; instead of CALayer *border = [CALayer init];.

    Please check this code :

    UIView+Border.h

    #import <UIKit/UIKit.h>
    
    @interface UIView (Border)
    @property (nonatomic) IBInspectable CGFloat addBorderTop;
    @property (nonatomic) IBInspectable CGFloat addBorderBottom;
    @property (nonatomic) IBInspectable CGFloat addBorderLeft;
    @property (nonatomic) IBInspectable CGFloat addBorderRight;
    
    @end
    

    UIView+Border.m

    #import "UIView+Border.h"
    
    IB_DESIGNABLE
    @implementation UIView (Border)
    
    @dynamic addBorderTop;
    @dynamic addBorderBottom;
    @dynamic addBorderLeft;
    @dynamic addBorderRight;
    
    - (void) setAddBorderTop: (CGFloat)newValue
    {
        [self addBorderUtility:0 y:0 width:self.frame.size.width height:newValue color:self.layer.borderColor];
    }
    
    - (void) setAddBorderBottom: (CGFloat) newValue
    {
        [self addBorderUtility:0 y:self.frame.size.height - newValue width:self.frame.size.width height:newValue color:self.layer.borderColor];
    }
    
    - (void) setAddBorderLeft: (CGFloat) newValue
    {
        [self addBorderUtility:0 y:0 width:newValue height:self.frame.size.height color:self.layer.borderColor];
    }
    
    - (void) setAddBorderRight: (CGFloat) newValue
    {
        [self addBorderUtility:self.frame.size.width - newValue y:0 width:newValue height:self.frame.size.height color:self.layer.borderColor];
    }
    
    - (void) addBorderUtility:(CGFloat)x y:(CGFloat)y width:(CGFloat)width  height:(CGFloat)height color:(CGColorRef)color
    {
        CALayer *border = [CALayer layer];
        border.backgroundColor = color;
        border.frame = CGRectMake(x, y, width, height);
        [self.layer addSublayer:border];
    }
    @end