简体   繁体   English

界面生成器中 UIView 的边框颜色不起作用?

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

I am trying to set up a view's layer properties via IB.我正在尝试通过 IB 设置视图的图层属性。 Everything works except for color of the border (property layer.borderColor ):除了边框的颜色(属性layer.borderColor )之外,一切都有效:

在此处输入图像描述

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.borderColor property never works via interface builder.而且,我仍然可以通过编程方式执行此操作,但我很好奇为什么layer.borderColor属性从不通过界面生成器工作。 I don't want to import QuartzCore , and then write extra line of code just because of this, seems like an overkill.我不想导入QuartzCore ,然后仅仅因为这个而编写额外的代码行,这似乎是一种矫枉过正。

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.这是因为 User Defined Runtime Attributes 面板中的Color类型创建了一个UIColor ,但layer.borderColor拥有一个CGColorRef类型。 Unfortunately, there's no way to assign a CGColorRef type in Interface Builder.不幸的是,没有办法在 Interface Builder 中分配CGColorRef类型。

However, this is possible through a proxy property.但是,这可以通过代理属性实现。 See Peter DeWeese's answer to a different question for a possible solution to this problem.有关此问题的可能解决方案,请参阅Peter DeWeese 对不同问题的回答 His answer defines a category that allows a proxy color to be set through Interface Builder.他的回答定义了一个类别,允许通过 Interface Builder 设置代理颜色。

You have to create Category for CALayer:您必须为 CALayer 创建类别:

CALayer+UIColor.h 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 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:然后在用户定义的运行时属性中,您可以使用它,如下图所示:

在此处输入图像描述

For Swift it is much more simple:对于Swift ,它要简单得多:

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:然后在 Xcode 中你可以像这样使用它:

在此处输入图像描述

Once you choose sth it is automatically added to your runtime attributes :一旦你选择了某事,它就会自动添加到你的运行时属性中:

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.现在在 Interface Builder 中,转到 Identity 检查器并将您的视图设置为 CustomView 类。

After that, check out your Attributes Inspector:之后,检查您的属性检查器:

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

No need to mess around with user defined runtime attributes anymore.不再需要弄乱用户定义的运行时属性。 And your changes will also show up on the canvas!您的更改也将显示在画布上!

My two cents for porting Bartłomiej Semańczyk's answer to Swift:将 Bartłomiej Semańczyk 对 Swift 的回答移植到我的两分钱:

Create an extension for CALayer in your view controller:在视图控制器中为 CALayer 创建一个扩展:

import UIKit

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

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

Use IBDesignable instead of Runtime Attributes it is more clear.使用 IBDesignable 而不是运行时属性更清楚。

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

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.重要的是取值并将 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

Of course, in the Interface Builder you're not setting the value on layer.borderColor , rather just on borderColor .当然,在 Interface Builder 中,您不会在layer.borderColor上设置值,而只是在borderColor上设置值。

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).在 Swift 中,您可以扩展UIButton类并添加一个@IBInspectable ,使您能够从情节提要中选择一种颜色并设置它的颜色(宽度为 1,可以更改)。 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为了使 CALayer KVC 兼容属性borderColorFromUIColor,只需实现

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".然后在 IB 中,将类型从“UIButton”更改为“UIButtonWithRoundBorder”。

Simple and handy too.简单又好用。 :) :)

swift4斯威夫特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)
   }
}

borderColor will not work UNLESS the borderWidth property of the layer is set to a value greater than 0 .除非图层的borderWidth属性设置为大于0的值,否则borderColor将不起作用。

Swift 3:斯威夫特 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:您可以在 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
    }
}

I think it may be because you have masksToBounds set to YES.我认为这可能是因为您将 maskToBounds 设置为 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.我不认为边界是在图层的边界内绘制的,所以它不会被绘制,因为你将所有东西都隐藏在它的边界之外。

You can customise border with 2 methods.您可以使用 2 种方法自定义边框。 First one is this.第一个是这个。 Just click on the object go to the identity inspector and set the attributes.只需单击对象转到身份检查器并设置属性。

在此处输入图像描述

Second one is this.第二个是这个。 make an IBOutlet of required object and put this code in view did load.制作所需对象的 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)
    }

Swift 5.2 - Answer of Fede Henze's 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
    }
}
}

try this in User Defined Runtime attribute :用户定义的运行时属性中试试这个:

  1. Key Path: layer.borderUIColor关键路径: layer.borderUIColor
  2. type: Color类型: Color
  3. Value: --you prefered color--值: --you prefered color--

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM