it-swarm.com.ru

Цвет границы UIView в Интерфейсном конструкторе не работает?

Я пытаюсь настроить свойства слоя представления через IB. Все работает, кроме цвета границы (свойство layer.borderColor):

enter image description here

Я помню, как столкнулся с этой проблемой год назад, и я закончил делать это программно. И все же, я могу сделать это программно, но мне любопытно, почему свойство layer.borderColor никогда не работает через конструктор интерфейса. Я не хочу импортировать QuartzCore, а затем писать дополнительную строку кода только потому, что это кажется излишним. 

60
0xSina

Это можно сделать, но это не встроенная функция. Это связано с тем, что тип Color на панели «Пользовательские атрибуты времени выполнения» создает UIColor, но layer.borderColor содержит тип CGColorRef. К сожалению, в Interface Builder невозможно назначить тип CGColorRef.

Однако это возможно через свойство прокси. Смотрите ответ Питера ДеВиса на другой вопрос о возможном решении этой проблемы. Его ответ определяет категорию, которая позволяет цвету прокси быть установленным через Интерфейсный Разработчик.

73
mopsled

Вы должны создать категорию для 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

А затем в Определяемые пользователем атрибуты среды выполнения Вы можете использовать его, как показано на рисунке ниже:

enter image description here

Для Swift это намного проще:

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

Тогда в Xcode вы можете использовать это так:

enter image description here

Как только вы выберете sth, он автоматически добавится к вашим атрибутам времени выполнения :

47
Bartłomiej Semańczyk

Мои два цента за портирование ответа Бартломея Семанчика на Свифта:

Создайте расширение для CALayer в вашем контроллере вида:

import UIKit

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

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

Скопируйте и вставьте этот класс:

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

Теперь в Интерфейсном Разработчике перейдите к Инспектору Идентичности и установите свое представление как класс CustomView.

После этого проверьте ваш инспектор атрибутов:

 Attributes inspector with the new IBInspectable options

Больше не нужно возиться с пользовательскими атрибутами времени выполнения. И ваши изменения также будут отображаться на холсте!

17
etayluz

Используйте 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
        }
    }
}
9
Fede Henze

Вот быстрый способ преодолеть это. Категории ...

@interface UIView (IBAppearance)

@property (nonatomic, strong) UIColor *borderColor;

@end

Вам не нужно хранить его, это просто Ницца, чтобы вы могли запросить позже. Важным моментом является получение значения и назначение слоя CIColor для UIColor.

#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

Конечно, в Интерфейсном Разработчике вы не устанавливаете значение на layer.borderColor, а просто на borderColor.

5
bainfu

В Swift вы можете расширить класс UIButton и добавить @IBInspectable, который позволит вам выбрать цвет из раскадровки и установить его цвет (с шириной 1, которую можно изменить) . Добавьте это в конце вашего контроллера представления :

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

Чтобы сделать CALayer KVC-совместимым для свойства borderColorFromUIColor, просто реализуйте 

layer.borderColorFromUIColor=[UIColor red];

У этой ссылки есть awnser

3
Mohit

Я столкнулся с той же проблемой, я обошел ее, создав собственный класс кнопок:

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

Вы можете установить значение для ключа "borderColor" в XIB и использовать:

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 не будет работать, ЕСЛИ ДЛЯ свойства borderWidth слоя не установлено значение больше 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

Вы можете настроить границу с помощью 2 методов .... Первый. Просто нажмите на объект, перейдите в инспектор личности и установите атрибуты.

 enter image description here

Второй это. сделать 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
akbar khan

Я думаю, что это может быть потому, что для masksToBounds установлено значение YES. Я не думаю, что граница рисуется в границах слоя, поэтому она не будет нарисована, поскольку вы прячете все за его пределами. 

0
Chris C