返回

子类化 UIButton 支持 spacing 并完美兼容 AutoLayout

IOS

引言

UIButton,作为 iOS 开发中不可或缺的控件,却一直存在着无法设置图像和文字间距的缺憾。传统的解决办法是通过调整 titleEdgeInsetsimageEdgeInsets,但这种方法不仅无法自动调整按钮大小,还会带来一系列兼容性问题。本文将介绍一种通过子类化 UIButton 来解决此问题的方案,该方案不仅支持 spacing 属性,而且完美兼容 AutoLayout

子类化 UIButton

要子类化 UIButton,只需创建一个新的 Swift 类并从 UIButton 继承即可。在这个子类中,我们将添加一个名为 spacing 的属性,用于设置图像和文字之间的间距。

class CustomButton: UIButton {
    var spacing: CGFloat = 0 {
        didSet {
            invalidateIntrinsicContentSize()
        }
    }
}

自定义内在内容大小

spacing 属性改变时,按钮的内在内容大小(intrinsicContentSize)需要随之改变。因此,需要覆盖 intrinsicContentSize 方法:

override var intrinsicContentSize: CGSize {
    let size = super.intrinsicContentSize
    return CGSize(width: size.width + spacing, height: size.height)
}

重写图像和文字布局

为了在 spacing 生效时正确布局图像和文字,需要重写 imageRect(forContentRect:)titleRect(forContentRect:) 方法:

override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
    let imageRect = super.imageRect(forContentRect: contentRect)
    imageRect.origin.x += spacing / 2
    return imageRect
}

override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
    let titleRect = super.titleRect(forContentRect: contentRect)
    titleRect.origin.x -= spacing / 2
    return titleRect
}

兼容 AutoLayout

为了确保子类化的 UIButtonAutoLayout 兼容,需要在 init(coder:) 方法中设置 translatesAutoresizingMaskIntoConstraintsfalse

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    translatesAutoresizingMaskIntoConstraints = false
}

使用示例

现在,就可以像使用普通的 UIButton 一样使用子类化的 CustomButton 了:

let button = CustomButton()
button.setTitle("按钮", for: .normal)
button.setImage(UIImage(named: "图标"), for: .normal)
button.spacing = 10
button.frame = CGRect(x: 100, y: 100, width: 100, height: 30)
view.addSubview(button)

总结

通过子类化 UIButton 并添加 spacing 属性,我们解决了 UIButton 无法设置图像和文字间距的痛点。该方案不仅简单易用,而且完美兼容 AutoLayout。希望这篇教程能为各位开发者带来便利,提升开发效率。