如何创建IBDesignable自定义视图?

时间:2017-03-17 14:19:54

标签: ios swift xcode interface-builder ibdesignable

我仍在提高iOS(Swift)的编程技巧。今天我正在考虑以一种好的方式创建一个UIView子类。我想创建自定义视图:

  • @IBDesignable - 我希望在storyboard / xib中看到我的视图渲染;
  • 可从代码
  • 创建

我知道init(withFrame) init() init(withDecoder) prepareForInterfacebuilder()等方法,但我不知道如何使用它们来最大限度地减少代码冗余。

例如,这是我的自定义UIButton

import UIKit

@IBDesignable
class SecurityButton: UIButton {

    @IBInspectable
    var color: UIColor = UIColor.black {
        didSet {
            setTitleColor(color, for: .normal)
            contentEdgeInsets = UIEdgeInsetsMake(0.0, 8.0, 0.0, 8.0)

            layer.borderWidth = 1.0
            layer.borderColor = color.cgColor
            layer.cornerRadius = 6.0
        }
    }
}

它运作良好,但我知道每当我设置一个新颜色时contentEdgeInsets = UIEdgeInsetsMake(0.0, 8.0, 0.0, 8.0) layer.cornerRadius = 6.0 layer.borderWidth = 1.0都会被调用。我应该在哪里放置此自定义设置以保持对自定义视图的要求?

修改

我不寻找修复我的例子。我正在寻找一个初始化自定义视图的好地方。假设您需要执行一些耗时的操作,但只需要创建视图。

2 个答案:

答案 0 :(得分:1)

您缺少功能

self.setNeedsDisplay()

您的代码应如下所示

import UIKit

@IBDesignable
class SecurityButton: UIButton {

    @IBInspectable
    var color: UIColor = UIColor.black {
        didSet {
            setTitleColor(color, for: .normal)
            contentEdgeInsets = UIEdgeInsetsMake(0.0, 8.0, 0.0, 8.0)

            layer.borderWidth = 1.0
            layer.borderColor = color.cgColor
            layer.cornerRadius = 6.0

            self.setNeedsDisplay()
        }
    }
}

这将调用将更新故事板视图的draw函数。 该函数应在didSet中作为last调用。现在它将在您设置颜色后显示。

我测试了它,在我在故事板中设置值颜色后,它在xcode中适用于我。

如果你想要它总是画画,不仅当你通过督察设置一个颜色时你可以使用draw(rect)函数它将会看起来如下

import UIKit

@IBDesignable
class SecurityButton: UIButton {

    @IBInspectable
    var color: UIColor = UIColor.black

    override func draw(_ rect: CGRect) {
        setTitleColor(color, for: .normal)
        contentEdgeInsets = UIEdgeInsetsMake(0.0, 8.0, 0.0, 8.0)

        layer.borderWidth = 1.0
        layer.borderColor = color.cgColor
        layer.cornerRadius = 6.0

        setNeedsDisplay()
    }
}

这将始终绘制边框,不仅仅是在界面检查器中设置时。

答案 1 :(得分:1)

您可以创建“自定义初始化”功能来处理设置任务。

所以,例如:

import UIKit

@IBDesignable
class SecurityButton: UIButton {

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        commonInit()
    }

    func commonInit() {

        layer.borderWidth = 1.0
        layer.borderColor = color.cgColor
        layer.cornerRadius = 6.0

        _contentEdgeInsets = UIEdgeInsets(top: 0.0, left: 8.0, bottom: 0.0, right: 8.0)
        updateEdgeInsets()
    }

    private var _contentEdgeInsets: UIEdgeInsets = UIEdgeInsets.zero {
        didSet { updateEdgeInsets() }
    }
    override public var contentEdgeInsets: UIEdgeInsets {
        get { return super.contentEdgeInsets }
        set { _contentEdgeInsets = newValue }
    }

    private func updateEdgeInsets() {
        let initialEdgeInsets = contentEdgeInsets

        let t = _contentEdgeInsets.top + initialEdgeInsets.top
        let l = _contentEdgeInsets.left + initialEdgeInsets.left
        let b = _contentEdgeInsets.bottom + initialEdgeInsets.bottom
        let r = _contentEdgeInsets.right + initialEdgeInsets.right

        super.contentEdgeInsets = UIEdgeInsets(top: t, left: l, bottom: b, right: r)
    }

    @IBInspectable
    var color: UIColor = UIColor.black {
        didSet {
            setTitleColor(color, for: .normal)
        }
    }

}

修改:自定义contentEdgeInsets的处理方式与大多数其他属性的处理方式略有不同。

@KamilHarasimowicz - 您的“问题编辑”声明“我不寻找修复我的示例。我正在寻找一个初始化自定义视图的好地方。” ...

我的初步答案就是这样 - 它显示了初始化自定义视图的位置。

但是,由于您的评论“storyboard不会在您的解决方案中呈现contentEdgeInsets”表明您确实 DO 希望修复您的示例(否则你自己就修好了),我已经编辑了我的答案。