web-dev-qa-db-fra.com

La couleur de bordure d'UIView dans le générateur Interface ne fonctionne pas?

J'essaie de définir les propriétés de la couche d'une vue via IB. Tout fonctionne sauf la couleur de la bordure (property layer.borderColor):

enter image description here

Je me rappelle avoir rencontré ce problème il y a un an et je l'ai finalement fait par programme. Et encore, je peux le faire par programme, mais je suis curieux de savoir pourquoi la propriété layer.borderColor ne fonctionne jamais via le constructeur d'interface. Je ne veux pas importer QuartzCore, puis écrire une ligne de code supplémentaire simplement à cause de cela, cela semble excessif. 

60
0xSina

C'est possible, mais ce n'est pas une fonctionnalité intégrée. En effet, le type Color du panneau Attributs d'exécution définis par l'utilisateur crée une variable UIColor, mais layer.borderColor contient un type CGColorRef. Malheureusement, il n'existe aucun moyen d'attribuer un type CGColorRef dans Interface Builder.

Cependant, cela est possible via une propriété proxy. Voir Réponse de Peter DeWeese à une autre question pour une solution possible à ce problème. Sa réponse définit une catégorie permettant de définir une couleur de proxy via Interface Builder.

73
mopsled

Vous devez créer une catégorie pour 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

Et ensuite dans Attributs d'exécution définis par l'utilisateur Vous pouvez l'utiliser tel quel sur l'image ci-dessous:

enter image description here

Pour Swift c'est beaucoup plus simple:

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

Ensuite, dans Xcode, vous pouvez l'utiliser comme ceci:

enter image description here

Une fois choisi, il est automatiquement ajouté à vos attributs d'exécution :

47

Mes deux cents pour porter la réponse de Bartłomiej Semańczyk à Swift:

Créez une extension pour CALayer dans votre contrôleur de vue:

import UIKit

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

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

Copiez et collez cette classe:

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

Maintenant, dans Interface Builder, accédez à l'inspecteur d'identité et définissez votre vue en tant que classe CustomView.

Après cela, vérifiez votre inspecteur d'attributs:

 Attributes inspector with the new IBInspectable options

Plus besoin de perdre son temps avec les attributs d'exécution définis par l'utilisateur. Et vos modifications apparaîtront également sur la toile!

17
etayluz

Utilisez IBDesignable au lieu d’attributs d’exécution, c’est plus clair.

Placez ce code dans n'importe quelle classe et modifiez les propriétés directement sur le 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
        }
    }
}
9
Fede Henze

Voici un moyen rapide de surmonter cela. Catégories ...

@interface UIView (IBAppearance)

@property (nonatomic, strong) UIColor *borderColor;

@end

Vous n'êtes pas obligé de le stocker, c'est juste Nice pour pouvoir interroger plus tard. L'important est de prendre la valeur et d'attribuer la CGColor de UIColor à la couche.

#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

Bien sûr, dans Interface Builder, vous ne définissez pas la valeur sur layer.borderColor, mais simplement sur borderColor.

5
bainfu

Dans Swift, vous pouvez étendre la classe UIButton et ajouter un @IBInspectable qui vous permettra de sélectionner une couleur dans le storyboard et de définir sa couleur (avec une largeur de 1 pouvant être modifiée) . Ajoutez-le à la fin de votre contrôleur de vue. :

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

Pour que CALayer KVC soit conforme à la propriété borderColorFromUIColor, implémentez simplement 

layer.borderColorFromUIColor=[UIColor red];

Ce lien a awnser

3
Mohit

J'ai rencontré le même problème, j'ai résolu ce problème en créant une classe de boutons personnalisée:

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
}

}

Ensuite, dans IB, remplacez le type "UIButton" par "UIButtonWithRoundBorder".

Simple et pratique aussi. :)

2
RainCast

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)
   }
}
0
Z King

Vous pouvez définir une valeur pour la clé "borderColor" dans le fichier XIB et utiliser:

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
Łukasz Kalbarczyk

borderColor ne fonctionnera pas SAUF si la propriété borderWidth du calque est définie sur une valeur supérieure à 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.
0
Malloc

Vous pouvez personnaliser la bordure avec 2 méthodes ..___ La première est la suivante. Il suffit de cliquer sur l'objet pour accéder à l'inspecteur d'identité et définir les attributs.

 enter image description here

La seconde est la suivante. faire un objet requis IBOutlet et mettre ce code en vue ne se charge.

@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
akbar khan

Je pense que c'est peut-être parce que vous avez défini les masquesToBounds sur OUI. Je ne pense pas que la frontière soit tracée dans les limites de la couche, elle ne sera donc pas tracée puisque vous cachez tout en dehors de ses limites 

0
Chris C