【问题标题】:How to create IBDesignable custom view?如何创建 IBDesignable 自定义视图?
【发布时间】:2017-03-17 14:19:54
【问题描述】:

我仍在提高我在 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。我应该把这个自定义设置放在哪里来满足我对自定义视图的要求?

编辑

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

【问题讨论】:

  • 我通常使用 awakeFromNib 在自定义视图中进行设置。
  • 我的自定义视图没有笔尖
  • 它是为 IB 调用的,而不是专门为 nib 调用的。也适用于故事板
  • 看我的要求。我想从代码中查看哪些是可设计和可创建的。当我从代码创建SecurityButton 时,awakeFromNib 会调用吗?

标签: ios swift xcode interface-builder ibdesignable


【解决方案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()
        }
    }
}

这将调用将更新情节提要视图的绘制函数。 该函数应该在 didSet 中作为最后一个调用现在它会在您设置颜色后显示。

在我在情节提要中设置值颜色后,我对其进行了测试,它在 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()
    }
}

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

【讨论】:

    【解决方案2】:

    您可以创建一个“自定义初始化”函数来处理设置任务。

    所以,例如:

    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 don't render contentEdgeInsets in your solution” 表明您实际上确实希望修复您的示例(否则你会自己修复它),我已经编辑了我的答案。

    【讨论】:

    • 故事板不在您的解决方案中呈现 contentEdgeInsets :(
    • 您的目标是将按钮限制contentEdgeInsets(0.0, 8.0, 0.0, 8.0) 吗?或者你想要contentEdgeInsets 设置在 IB plus 8.0 左右?
    • 在这种情况下,我想在故事板预览中看到这个边缘,但我的目标是在自定义视图中找到一个可以放置自定义视图的所有更改的位置。请检查我的问题编辑。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-24
    • 2012-11-18
    • 2014-02-26
    相关资源
    最近更新 更多