87

I Set CornerRadius and BorderWidth for UIbutton in User Defined Runtime Attributes. Without adding layer.borderColor it works Well and Display border in black color. But when add layer.borderColor does not work(does not show border).

enter image description here

Donald Duck
  • 8,409
  • 22
  • 75
  • 99
Mohamed Jaleel Nazir
  • 5,776
  • 3
  • 34
  • 48

8 Answers8

163

For Swift:

enter image description here

Swift 3:

extension UIView {

    @IBInspectable var cornerRadius: CGFloat {
        get {
            return layer.cornerRadius
        }
        set {
            layer.cornerRadius = newValue
            layer.masksToBounds = newValue > 0
        }
    }

    @IBInspectable var borderWidth: CGFloat {
        get {
            return layer.borderWidth
        }
        set {
            layer.borderWidth = newValue
        }
    }

    @IBInspectable var borderColor: UIColor? {
        get {
            return UIColor(cgColor: layer.borderColor!)
        }
        set {
            layer.borderColor = newValue?.cgColor
        }
    }
}

Swift 2.2:

extension UIView {

    @IBInspectable var cornerRadius: CGFloat {
        get {
            return layer.cornerRadius
        }
        set {
            layer.cornerRadius = newValue
            layer.masksToBounds = newValue > 0
        }
    }

    @IBInspectable var borderWidth: CGFloat {
        get {
            return layer.borderWidth
        }
        set {
            layer.borderWidth = newValue
        }
    }

    @IBInspectable var borderColor: UIColor? {
        get {
            return UIColor(CGColor: layer.borderColor!)
        }
        set {
            layer.borderColor = newValue?.CGColor
        }
    }
}
brnunes
  • 1,943
  • 26
  • 30
Mohamed Jaleel Nazir
  • 5,776
  • 3
  • 34
  • 48
  • 1
    Neat, however XCode(Version 8.3.3 (8E3004b)) doesn't show result in preview, is this right and no way to change(except creating custom view)? – Konstantin Berkov Jul 17 '17 at 09:37
  • I know this answer is old (and great by the way), but I need to ask if this would affect the compiling time or something like that? adding this to all the UIView? – Vertig0 Sep 22 '17 at 19:51
  • @Vertig0 adding what to the UIView? 3 properties? Absolutely not. – J. Doe Oct 09 '17 at 22:44
97

I got answer. Change borderColor instead of layer.borderColor:

Xcode snippet

and add this code in .m file:

#import <QuartzCore/QuartzCore.h>
@implementation CALayer (Additions)

- (void)setBorderColorFromUIColor:(UIColor *)color
{
    self.borderColor = color.CGColor;
}

@end

Tick properties in Attribute Inspector

Attribute Inspector

Pranav Kasetti
  • 8,770
  • 2
  • 50
  • 71
Mohamed Jaleel Nazir
  • 5,776
  • 3
  • 34
  • 48
  • 6
    @jithin I wrote it as a Swift extension, here's the code: extension CALayer { func setBorderColorFromUIColor(color: UIColor) { self.borderColor = color.CGColor } } – Guy Jan 08 '16 at 23:08
  • 1
    trick worked. partially. how on earth am I getting black border color even though i specified red color?!!!!!! any ideas? anyone? – static0886 Jan 22 '16 at 12:41
  • @static0886: It was because of what color you're applying is not set to the border. As per my understanding we can't set border color from storyboard as this property won't get reflected in the UIComponent at runtime. By default it is black color. If you want give a trial by removing the color property from Attributes. – Javeed Mar 30 '16 at 08:56
  • For swift you can set it as: self.button.layer.borderColor = – Sam Apr 19 '16 at 01:02
  • That layer.borderColorFromUIColor worked for me in the story board. Thank you. – Ramakrishna Jul 05 '16 at 10:22
  • hello i am create CustomeView class in objective c but its not showing in my storyboard Plz help me. – Pooja Srivastava Feb 06 '17 at 10:22
58

Swift 4, Xcode 9.2 - Use IBDesignable and IBInspectable to build custom controls and live preview the design in Interface Builder.

Here is a sample code in Swift, place just below the UIKit in ViewController.swift:

@IBDesignable extension UIButton {

    @IBInspectable var borderWidth: CGFloat {
        set {
            layer.borderWidth = newValue
        }
        get {
            return layer.borderWidth
        }
    }

    @IBInspectable var cornerRadius: CGFloat {
        set {
            layer.cornerRadius = newValue
        }
        get {
            return layer.cornerRadius
        }
    }

    @IBInspectable var borderColor: UIColor? {
        set {
            guard let uiColor = newValue else { return }
            layer.borderColor = uiColor.cgColor
        }
        get {
            guard let color = layer.borderColor else { return nil }
            return UIColor(cgColor: color)
        }
    }
}

If you go to the Attributes inspectable of the view, you should find these properties visually, edit the properties:

enter image description here

The changes are also reflected in User Defined Runtime Attributes:

enter image description here

Run in build time and Voila! you will see your clear rounded button with border.

enter image description here

Cons Bulaquena
  • 2,083
  • 2
  • 26
  • 24
9

The explanation, perhaps being lost in some of the other answers here:

The reason that this property is not being set is that layer.borderColor needs a value with type CGColor.

But only UIColor types can be set via Interface Builder's User Defined Runtime Attributes!

So, you must set a UIColor to a proxy property via Interface Builder, then intercept that call to set the equivalent CGColor to the layer.borderColor property.

This can be accomplished by creating a Category on CALayer, setting the Key Path to a unique new "property" (borderColorFromUIColor), and in the category overriding the corresponding setter (setBorderColorFromUIColor:).

pkamb
  • 33,281
  • 23
  • 160
  • 191
1

This works for me.

Swift 3, Xcode 8.3

Identity inspector (UIButton in this case

CALayer extension:

extension CALayer {
var borderWidthIB: NSNumber {
    get {
        return NSNumber(value: Float(borderWidth))
    }
    set {
        borderWidth = CGFloat(newValue.floatValue)
    }
}
var borderColorIB: UIColor? {
    get {
        return borderColor != nil ? UIColor(cgColor: borderColor!) : nil
    }
    set {
        borderColor = newValue?.cgColor
    }
}
var cornerRadiusIB: NSNumber {
    get {
        return NSNumber(value: Float(cornerRadius))
    }
    set {
        cornerRadius = CGFloat(newValue.floatValue)
    }
}

}

pkamb
  • 33,281
  • 23
  • 160
  • 191
Jovan Stankovic
  • 4,661
  • 4
  • 27
  • 16
1

There is a much better way to do this! You should use @IBInspectable. Check out Mike Woelmer's blog entry here: https://spin.atomicobject.com/2017/07/18/swift-interface-builder/

It actually adds the feature to IB in Xcode! Some of the screenshots in other answers make it appear as though the fields exist in IB, but at least in Xcode 9 they do not. But following his post will add them.

pkamb
  • 33,281
  • 23
  • 160
  • 191
cdeerinck
  • 688
  • 6
  • 17
  • I tried this approach and it made Xcode really slow. Is it happening to you all as well? – Meep Feb 09 '20 at 22:48
0

In case of Swift, function doesn't work. You'll need a computed property to achieve the desired result:

extension CALayer {
    var borderColorFromUIColor: UIColor {
        get {
            return UIColor(CGColor: self.borderColor!)
        } set {
            self.borderColor = newValue.CGColor
        }
    }
}
Furqan Khan
  • 504
  • 4
  • 12
-1

You have set the data values for the radius and the width set to be a string, but it should properly be to be set to a number, not a string

When you get it working, this will not be visible while looking at the storyboard, but will be when the app is running unless you have taken steps to make it @IBDesigneable.

Alex Zavatone
  • 4,106
  • 36
  • 54