UIView's border color in Interface builder doesn't work?

I am trying to set up a view’s layer properties via IB. Everything works except for color of the border (property layer.borderColor):

enter image description here

  • Cannot call value of non-function type 'String'
  • Cropped UIButton Title
  • iOS, Use struct in Objective C, struct values not assignable from super view
  • performSelector may cause a leak because its selector is unknown
  • Storyboard reference on iOS below 9.0
  • Unit Testing Example with OCUnit
  • I remember running into this problem a year ago and I ended up doing it programatically. And still, I can do this programmatically, but I am curious why the layer.borderColorproperty never works via interface builder. I don’t want to import QuartzCore, and then write extra line of code just because of this, seems like an overkill.

    12 Solutions Collect From Internet About “UIView's border color in Interface builder doesn't work?”

    It’s possible to do this, but it’s not a built-in feature. This is because the Color type in the User Defined Runtime Attributes panel creates a UIColor, but layer.borderColor holds a CGColorRef type. Unfortunately, there’s no way to assign a CGColorRef type in Interface Builder.

    However, this is possible through a proxy property. See Peter DeWeese’s answer to a different question for a possible solution to this problem. His answer defines a category that allows a proxy color to be set through Interface Builder.

    You have to create Category for CALayer:

    CALayer+UIColor.h

    #import <QuartzCore/QuartzCore.h>
    #import <UIKit/UIKit.h>
    
    @interface CALayer(UIColor)
    
    // This assigns a CGColor to borderColor.
    @property(nonatomic, assign) UIColor* borderUIColor;
    
    @end
    

    CALayer+UIColor.m

    #import "CALayer+UIColor.h"
    
    @implementation CALayer(UIColor)
    
    - (void)setBorderUIColor:(UIColor*)color {
        self.borderColor = color.CGColor;
    }
    
    - (UIColor*)borderUIColor {
        return [UIColor colorWithCGColor:self.borderColor];
    }
    
    @end
    

    And then in User Defined Runtime attributes You can use it as it is on image below:

    enter image description here

    For Swift it is much more simple:

    @IBInspectable var borderColor: UIColor? {
        didSet {
            layer.borderColor = borderColor?.CGColor
            layer.borderWidth = 1
        }
    }
    

    Then in Xcode you can use it like this:

    enter image description here

    Once you choose sth it is automatically added to your runtime attributes:

    My two cents for porting Bartłomiej Semańczyk’s answer to Swift:

    Create an extension for CALayer in your view controller:

    import UIKit
    
    extension CALayer {
        func borderUIColor() -> UIColor? {
            return borderColor != nil ? UIColor(CGColor: borderColor!) : nil
        }
    
        func setBorderUIColor(color: UIColor) {
            borderColor = color.CGColor
        }
    }
    

    Cut and Paste this class:

    import UIKit
    
    @IBDesignable class CustomView : UIView {
      @IBInspectable var borderColor: UIColor = UIColor.clearColor() {
        didSet {
          layer.borderColor = borderColor.CGColor
        }
      }
    
      @IBInspectable var borderWidth: CGFloat = 0 {
        didSet {
          layer.borderWidth = borderWidth
        }
      }
    
      @IBInspectable var cornerRadius: CGFloat = 0 {
        didSet {
          layer.cornerRadius = cornerRadius
        }
      }
    }
    

    Now in Interface Builder, go to the Identity inspector and set your view as a CustomView class.

    Now checkout out your Attributes Inspector:
    enter image description here

    No need to mess around with user defined runtime attributes anymore. And your changes will also show up on the canvas!!!

    Here’s a quick way to overcome this. Categories…

    @interface UIView (IBAppearance)
    
    @property (nonatomic, strong) UIColor *borderColor;
    
    @end
    

    You don’t have to store it, it’s just nice so you can query later. The important thing is taking the value and assigning the UIColor’s CGColor to the layer.

    #import <objc/runtime.h>
    
    #define BORDER_COLOR_KEYPATH @"borderColor"
    
    @implementation UIView (IBAppearance)
    
    - (void)setBorderColor:(UIColor *)borderColor {
        UIColor *bc = objc_getAssociatedObject(self, BORDER_COLOR_KEYPATH);
        if(bc == borderColor) return;
        else {
            objc_setAssociatedObject(self, BORDER_COLOR_KEYPATH, borderColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
            self.layer.borderColor = [borderColor CGColor];
        }
    }
    
    - (UIColor *)borderColor {
        return objc_getAssociatedObject(self, BORDER_COLOR_KEYPATH);
    }
    
    @end
    

    Of course, in the Interface Builder you’re not setting the value on layer.borderColor, rather just on borderColor.

    Use IBDesignable instead of Runtime Attributes it is more clear.

    Put this code in any class and edit the properties direct on the storyboard.

    import UIKit
    
    @IBDesignable extension UIView {
        @IBInspectable var borderColor:UIColor? {
            set {
                layer.borderColor = newValue!.CGColor
            }
            get {
                if let color = layer.borderColor {
                    return UIColor(CGColor:color)
                }
                else {
                    return nil
                }
            }
        }
        @IBInspectable var borderWidth:CGFloat {
            set {
                layer.borderWidth = newValue
            }
            get {
                return layer.borderWidth
            }
        }
        @IBInspectable var cornerRadius:CGFloat {
            set {
                layer.cornerRadius = newValue
                clipsToBounds = newValue > 0
            }
            get {
                return layer.cornerRadius
            }
        }
    }
    

    In Swift, you can extend the UIButton class and add an @IBInspectable that will enable you to select a color from storyboard and set it’s color (with width of 1 which can be changed).
    Add this at the end of your view controller:

    extension UIButton{
        @IBInspectable var borderColor: UIColor? {
            get {
                return UIColor(CGColor: layer.borderColor!)
            }
            set {
                layer.borderColor = newValue?.CGColor
                layer.borderWidth = 1
            }
        }
    }
    

    In order to make CALayer KVC-compliant for the property borderColorFromUIColor, simply implement the

    layer.borderColorFromUIColor=[UIColor red];
    

    This link have awnser

    I met the same issue, I worked around it by creating a custom button class:

    class UIButtonWithRoundBorder: UIButton {
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.layer.cornerRadius = 6
        self.layer.borderWidth = 1
        self.layer.borderColor = UIColor.whiteColor().CGColor
        self.clipsToBounds = true
    }
    
    }
    

    Then in IB, change the type from “UIButton” to “UIButtonWithRoundBorder”.

    Simple and handy too. 🙂

    I think it may be because you have masksToBounds set to YES. I don’t think the border is drawn within the bounds of the layer, so it won’t be drawn since you’re hiding everything outside of its bounds.

    borderColor will not work UNLESS the borderWidth property of the layer is set to a value greater than 0.

    Swift 3:

    button.layer.borderColor = UIColor.white.cgColor
    button.layer.borderWidth = 1.0 // Default value is 0, that's why omitting this line will not make the border color show.
    

    You can set a value for the “borderColor” key in the XIB and use:

    extension UIView {
    
        open override func setValue(_ value: Any?, forKey key: String) {
            guard key == "borderColor", let color = value as? UIColor else {
                super.setValue(value, forKey: key)
                return
            }
    
            layer.borderColor = color.cgColor
        }
    }