Подтвердить что ты не робот

Можете ли вы добавить свойства IBDesignable в UIView с помощью категорий/расширений?

Для тех, кто не знает, о чем я говорю, Xcode 6.0 добавил новые функции, IBDesignable и IBInspectable.

Когда вы помечаете свои пользовательские представления свойствами IBInspectable, эти свойства отображаются в Инспекторе атрибутов в IB.

Аналогично, когда вы помечаете пользовательский подкласс UIView с IBDesignable, Xcode компилирует ваши представления и вызывает код для рендеринга ваших объектов вида прямо в окне Xcode, чтобы вы могли видеть, как они выглядят.

Метод добавления атрибутов IBDesignable и IBInspectable к пользовательским представлениям почти идентичен в Swift и Objective-C. Свойства IBInspectable отображаются в инспекторе атрибутов интерфейса Builder независимо от того, какой язык вы используете для их определения.

Я создал категорию UIView в Objective-C и расширение UIView в Swift, которое поддерживает свойства borderWidth, cornerRadius, borderColor и layerBackgroundColor слоя, лежащего в основе представления, как свойства представления. Если вы измените свойство, расширение/категория делает преобразование по мере необходимости и перенаправляет изменение на слой.

Часть IBInspectable отлично работает. Я вижу и могу установить новые свойства в инспекторе атрибутов IB.

Я мог бы поклясться, что на прошлой неделе атрибут IBDesignable в моей категории категорий/расширении тоже работал, и я мог видеть свою собственную визуализацию категорий UIView в IB с изменением атрибутов слоя. На этой неделе он не работает.

Был ли я галлюцинацией?

Можно ли использовать категории/расширения существующих системных классов свой пользовательский интерфейс в Interface Builder, когда они настроены с помощью IBDesignable?

4b9b3361

Ответ 1

После публикации этого вопроса я узнал, что @IBDesignable не работает для расширений класса. Вы можете добавить тег, но он не имеет никакого эффекта.

Ответ 2

@IBDesignable работать с расширением UIView только в пользовательском классе. Например. UILabel является подклассом UIView по умолчанию. Он не будет работать там, но если вы создадите собственный класс под названием MyUILabel для подкласса UILabel. присвойте классу MyUILabel метке, над которой вы работаете. Тогда ваш угловой радиус в расширении UIView будет работать с этим MyUILabel.  (Я думаю, что в первую неделю он работает для вас, потому что вы имеете дело с каким-то специальным классом.)

Ответ 3

Я сделал эту работу для своего варианта использования, имея один @IBDesignable UIView, который я установил как верхний вид в моем контроллере представления. В моем конкретном случае использование стилей ClassyKit видимо в интерфейсе Builder в представлении UIKit по умолчанию, но для этого не требуется подкласс, и он отлично работает.

Вот пример того, как вы могли настроить его:

// in Interface Builder set the class of your top view controller view to this
@IBDesignable class DesignableView: UIView {
}

extension UIView {
    open override func prepareForInterfaceBuilder() {
        subviews.forEach {
            $0.prepareForInterfaceBuilder()
        }
    }
}

extension UILabel {
// just an example of doing something
    open override func prepareForInterfaceBuilder() {
        layer.cornerRadius = 8
        layer.masksToBounds = true
        backgroundColor = .red
        textColor = .green
    }
}

Ответ 4

Мне удалось заставить его работать с кодом ниже, но побочным эффектом является то, что несколько раз агент IB в раскадровке падает, потому что он должен обновлять слишком много элементов интерфейса. Перезапуск Xcode временно устраняет проблему до следующего сбоя. Возможно, что проблема OP обращена к

@IBDesignable
extension UIView
{

    @IBInspectable
    public var cornerRadius: CGFloat
    {
        set (radius) {
            self.layer.cornerRadius = radius
            self.layer.masksToBounds = radius > 0
        }

        get {
            return self.layer.cornerRadius
        }
    }

    @IBInspectable
    public var borderWidth: CGFloat
    {
        set (borderWidth) {
            self.layer.borderWidth = borderWidth
        }

        get {
            return self.layer.borderWidth
        }
    }

    @IBInspectable
    public var borderColor:UIColor?
    {
        set (color) {
            self.layer.borderColor = color?.cgColor
        }

        get {
            if let color = self.layer.borderColor
            {
                return UIColor(cgColor: color)
            } else {
                return nil
            }
        }
    }
}

Вот почему я пытаюсь добавить предложение where, чтобы уменьшить подклассы, которые должны расширить эту функциональность: Общий IBDesginables расширение UIView

Ответ 5

Этот блок кода работает хорошо для меня.

import UIKit

public extension UIView {
    @IBInspectable public var cornerRadius: CGFloat {
        get {
            return layer.cornerRadius
        }
        set {
            layer.cornerRadius = newValue
            layer.masksToBounds = newValue > 0
        }
    }
}

ПРИМЕЧАНИЕ Это может не сработать при импорте из фреймворка. Сейчас я пытаюсь выяснить причину.