UIView 的 Interface Builder 边框颜色不起作用?

我试图建立一个视图的层属性通过 IB。除了边框的颜色(属性 layer.borderColor) ,其他都可以使用:

enter image description here

我记得一年前遇到过这个问题,最后我用编程方式解决了它。尽管如此,我还是可以通过编程来实现这一点,但是我很好奇为什么 abc 0属性从来不通过 Interface Builder 工作。我不想导入 QuartzCore,然后编写额外的代码行只是因为这个,似乎是一个过度杀伤。

65616 次浏览

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.

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.

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.

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

layer.borderColorFromUIColor=[UIColor red];

This link have awnser

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:

import QuartzCore


extension CALayer {
@IBInspectable var borderUIColor: UIColor? {
get {
guard let borderColor = borderColor else { return nil }
return UIColor(cgColor: borderColor)
}
        

set {
borderColor = newValue?.cgColor
}
}
}

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
}
}

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
}
}
}

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
}
}
}

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. :)

Copy and paste this class:

import UIKit


@IBDesignable class BorderView : UIView {
@IBInspectable var borderColor: UIColor = .clear {
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.

After that, check out your Attributes Inspector:

Attributes inspector with the new IBInspectable options

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

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
}
}

You can customise border with 2 methods. First one is this. Just click on the object go to the identity inspector and set the attributes.

enter image description here

Second one is this. make an IBOutlet of required object and put this code in view did load.

@IBOutlet weak var uploadView: UIView!


override func viewDidLoad() {
super.viewDidLoad()


uploadView.layer.cornerRadius = 10
uploadView.layer.borderWidth = 1.0
uploadView.layer.borderColor = #colorLiteral(red: 0.08235294118, green: 0.5058823529, blue: 0.9450980392, alpha: 1)
}

swift4

extension CALayer {


open override func setValue(_ value: Any?, forKey key: String) {


/// If key is borderColor, and the value is the type of a UIColor.
if key == "borderColor" , let color = value as? UIColor {


/// After converting UIColor to CGColor, call the system method.
return super.setValue(color.cgColor, forKey: key)
}


super.setValue(value, forKey: key)
}
}

Swift 5.2 - Answer of Fede Henze's

@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
}
}
}

try this in User Defined Runtime attribute:

  1. Key Path: layer.borderUIColor
  2. type: Color
  3. Value: --you prefered color--