UIButton 左对齐图像和居中文本

UIButton align image left and center text

简介:

我有一个 class,它 UIButton 继承了 。在此 class 中,我想 更新 属性,例如 titleEdgeInsetsimageEdgeInsetscontentHorizontalAlignment.

我的第一个方法是使用 layoutSubviews:

override func layoutSubviews() {
    super.layoutSubviews()

    // update properties 
}

layoutSubviews 创建了一个 无限循环 ,因此我搜索了替代方法。

我的问题:

使用 willMove 方法 更新 UIButton 属性是一种常见的方法吗?

override func willMove(toWindow newWindow: UIWindow?) {
    super.willMove(toWindow: newWindow)

    // update properties
}

如果不是,为什么?

我的目标是将按钮的 imageView 左对齐(带内边距)并使文本居中。

更新:

我需要按钮 frame.size 和 bounds.width 来计算文本和图像视图的位置

您上面提到的所有属性都可以在UIButtoninit中设置,完全没有必要在layoutSubviewswillMove(toWindow中设置。 layoutSubviews 将被多次调用,因此在这里重新设置这些属性是没有意义的。 willMove(toWindow 将在将按钮添加到某个视图并加载按钮时调用,但您不必等到那时再设置这些属性。因为你已经有了按钮的子类,所以我建议做

class SomeButton: UIButton {
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.titleEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        self.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        self.contentHorizontalAlignment = .center
    }

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

顺便说一下,不建议创建 UIButton 的子类,因此如果您只想将这些属性分配给您的按钮,您可以扩展到 UIButton

extension UIButton {
    func applyStyle() {
        self.titleEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        self.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        self.contentHorizontalAlignment = .center
    }
}

编辑:

这是你想要的吗??

无论文本是什么,文本总是居中,图像在其左侧,并有 10 像素的内边距

编辑 2:

正如 OP 确认的那样,他希望按钮的样式如上图所示,发布代码以实现相同的效果

class SomeButton: UIButton {
    var titleFont: UIFont! = nil
    var textSize: CGFloat = 0
    let imageWidth: CGFloat = 20
    let buttonHeight: CGFloat = 30

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.titleFont = titleLabel!.font
        self.setTitle("here", for: .normal)
        self.setTitleColor(UIColor.red, for: .normal)
        self.setImage(UIImage(named: "hand"), for: .normal)
        self.backgroundColor = UIColor.green
    }

    override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
        if let string = self.title(for: .normal) {
            textSize = string.widthOfString(usingFont: self.titleFont)
            //30 because imageWidth + 10 padding
            return CGRect(origin: CGPoint(x: 30, y: 0), size: CGSize(width: textSize + 30, height: buttonHeight))
        }
        return CGRect.zero
    }

    override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
        return CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: imageWidth, height: buttonHeight))
    }
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override var intrinsicContentSize: CGSize {
        //60 because you need eauql padding on both side 30 + 30 = 60
        return CGSize(width: textSize + 60, height: buttonHeight)
    }
}

extension String {

    func widthOfString(usingFont font: UIFont) -> CGFloat {
        let fontAttributes = [NSAttributedString.Key.font: font]
        let size = self.size(withAttributes: fontAttributes)
        return size.width
    }
}

希望对您有所帮助