Can you add IBDesignable properties to UIView using categories/extensions?

跟風遠走 提交于 2019-12-01 02:25:30

Since posting this question I've learned that @IBDesignable does not work for class extensions. You can add the tag, but it has no effect.

Paulius Vindzigelskis

I was able to make it work with code below, but the side effect is that some times IB agent in storyboard crashes because it has to refresh too many UI elements. Restarting Xcode fixes problem temporarily until next crash. Maybe that's the problem OP is facing

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

That's why I am trying to add where clause to reduce subclasses which should extend this functionality: Generic IBDesginables UIView extension

@IBDesignable work with UIView extension only in custom class.For example. UILabel is a default sub-class of UIView. It won't work there, but if you make a custom class called MyUILabel subclassing UILabel. assign the MyUILabel class to the Label your are working on. Then your corner radius in UIView extension will work of this MyUILabel. ( I guess the first week it work for you is because you are dealing with some custom class.)

I've made this work for my use case by having one @IBDesignable UIView that I set as the top view in my view controller. My particular use case is making ClassyKit styling visible in Interface Builder on the default UIKit views without have to subclass just for that and it's working great.

Here's an example of how you could set it up:

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

This code block is working well for me.

import UIKit

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

NOTE It might not work when being imported from a framework. I am trying to find out the reason now.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!