如何创建 IBDesignable 自定义视图?

Posted

技术标签:

【中文标题】如何创建 IBDesignable 自定义视图?【英文标题】:How to create IBDesignable custom view? 【发布时间】: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 调用的。也适用于故事板 developer.apple.com/reference/objectivec/nsobject/… 看我的要求。我想从代码中查看哪些是可设计和可创建的。当我从代码创建SecurityButton 时,awakeFromNib 会调用吗? 【参考方案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 左右? 在这种情况下,我想在故事板预览中看到这个边缘,但我的目标是在自定义视图中找到一个可以放置自定义视图的所有更改的位置。请检查我的问题编辑。

以上是关于如何创建 IBDesignable 自定义视图?的主要内容,如果未能解决你的问题,请参考以下文章

将故事板指南标题设置为 @IBInspectable 值,以便快速自定义 @IBDesignable 视图?

如何使用创建的自定义 IBDesignable 类从情节提要中更改按钮的角半径

IBOutlet 在 IBDesignable 类中为零

使用Swift在Xcode 9中不显示IBDesignable UI

无法将自定义 IBDesignable 类链接到情节提要上的 UIButton

如何使用 @IBDesignable 和 @IBInspectable 制作 uitextfield 的自定义子类并在那里我可以从左侧设置占位符填充