UIView的“界面”构建器中的边框颜色不起作用?


69

我试图通过IB设置视图的图层属性。一切正常,除了边框的颜色(属性layer.borderColor):

enter image description here

我记得一年前遇到此问题,但最终还是以编程方式完成了此工作。而且,我可以通过编程方式执行此操作,但是我很好奇为什么该layer.borderColor属性永远无法通过界面生成器工作。我不想import QuartzCore,然后仅仅因为这个原因而编写额外的代码行,这似乎有点过头了。


1
“正因为如此,编写额外的代码行,似乎是一种

@ H2CO3大声笑...我只是不喜欢编写我不必编写的代码
0xSina 2013年

我已经在过去犯了这个错误。我希望大家都知道它..否则,检查从这个第一个答案:stackoverflow.com/questions/3980251/...
chuthan20

1
您可以使用代理属性来做到这一点!请在stackoverflow.com/questions/12301256/…中
Peter DeWeese 2013年

Answers:


79

可以这样做,但这不是内置功能。这是因为“Color用户定义的运行时属性”面板中的类型会创建一个UIColor,但会layer.borderColor保留一个CGColorRef类型。不幸的是,无法CGColorRef在Interface Builder中分配类型。

但是,这可以通过代理属性来实现。有关此问题的可能解决方案,请参阅Peter DeWeese对另一个问题的回答。他的答案定义了一个类别,该类别允许通过Interface Builder设置代理颜色。


48

您必须为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

然后在“用户定义的运行时”属性中,可以按照下图所示使用它:

在此处输入图片说明

对于Swift,它要简单得多:

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

然后在Xcode中可以像这样使用它:

在此处输入图片说明

选择sth后,它将自动添加到您的运行时属性中


这是最简单的解决方案,也是我实施的解决方案。缺点是您可能会忘记它的存在(只有几行!)。
劳埃德·萨金特

为什么选择borderUIColor属性assign代替strong?这是一个对象类型,这不会导致问题吗?
raven_raven

^因为它不保存值,所以将其传递。
tGilani '17

25

复制并粘贴此类:

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

现在,在Interface Builder中,转到身份检查器,然后将视图设置为CustomView类。

之后,请检查您的属性检查器:

具有新IBInspectable选项的属性检查器

不再需要弄乱用户定义的运行时属性。您所做的更改也将显示在画布上!


19

我为将BartłomiejSemańczyk的答案移植到Swift而付出的两分钱:

在视图控制器中为CALayer创建扩展:

import UIKit

extension CALayer {
    func borderUIColor() -> UIColor? {
        return borderColor != nil ? UIColor(CGColor: borderColor!) : nil
    }

    func setBorderUIColor(color: UIColor) {
        borderColor = color.CGColor
    }
}

您好@Eduardo,那我将如何在Storyboard中使用它?
卡伦

11

使用IBDesignable代替运行时属性会更清楚。

将此代码放在任何类中,然后直接在情节提要上编辑属性。

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

将这些内容应用于多个项目时,可以省去很多头痛的事情。光滑的小花絮。
哈利根(Haligen)

抱歉,这行不通。我自己尝试过。@IBDesignable在UIView扩展上不起作用。stackoverflow.com/questions/29906855/...
etayluz

刚刚尝试使用Swift 3.0解决了一些微小的大小写问题。可惜我以前不知道这一点。
尚尚

从Xcode 9和Swift 3开始,它实际上在运行时起作用。它只是不显示界面构建器中的更改。
哈里森·史密斯

5

这是克服此问题的快速方法。分类...

@interface UIView (IBAppearance)

@property (nonatomic, strong) UIColor *borderColor;

@end

您不必存储它,这很好,因此您以后可以查询。重要的是获取值并将UIColor的CGColor分配给图层。

#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

当然,在Interface Builder中,您不是将值设置为layer.borderColor,而是将值设置为borderColor


我认为没有必要使用关联的对象,因为可能会发生某些事情,并且您的borderColor将与layer.borderColor不同步。只需返回[UIColor colorWithCGColor:self.layer.borderColor]
storoj 2013年

1
你绝对是正确的@storoj。这是一种用于添加属性并能够使用类别存储它们的模式。在这里被误用了。
bainfu 2014年

5

在Swift中,您可以扩展UIButton类并添加@IBInspectable,使您能够从情节提要中选择一种颜色并设置其颜色(宽度为1,可以更改)。在您的视图控制器的末尾添加:

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

3

为了使CALayer KVC兼容属性borderColorFromUIColor,只需实现

layer.borderColorFromUIColor=[UIColor red];

该链接有遮篷


谢谢您的光临,也谢谢您的苹果!!
Fattie

2

我遇到了同样的问题,我通过创建自定义按钮类来解决此问题:

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
}

}

然后在IB中,将类型从“ UIButton”更改为“ UIButtonWithRoundBorder”。

也简单方便。:)


2

迅捷4

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

请为您的代码提供一些说明,并提供帮助解决此问题的方法
-Sinto

1

borderColor除非borderWidth图层的属性设置为大于0的值,否则它将不起作用。

斯威夫特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.

您的答案与问题无关。张贴者说他知道如何编程。此外,您可以在屏幕快照中看到他已经将borderWidth设置为> 1。他询问有关在IB中专门进行此操作的问题。
jungledev

0

我认为可能是因为您将masksToBounds设置为YES。我不认为边界是在图层边界内绘制的,因此不会绘制边界,因为您将所有内容都隐藏在边界之外。


嗯...不是@我的桌面,所以可以尝试一下,但是如果我将masksToBounds设置为NO,那么我就不能使UIImageView变圆/转角半径:(
0xSina 2013年

0

您可以在XIB中为“ borderColor”键设置一个值,并使用:

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

0

您可以使用2种方法自定义边框。第一个是这个。只需单击对象,转到身份检查器并设置属性。

在此处输入图片说明

第二个是这个。制作所需对象的IBOutlet并将此代码放入已加载的视图中。

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

0

Swift 5.2-Fede Henze的答案

@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
    }
}
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.