このソリューションは Swift 3 で動作し、元のコンテンツと画像の端のインセットを尊重しながら、タイトル ラベルを常に使用可能なスペースの中央に配置するため、余白の調整がはるかに簡単になります。
メソッドをオーバーライドtitleRect(forContentRect:)
し、正しいフレームを返します。
@IBDesignable
class LeftAlignedIconButton: UIButton {
override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
let titleRect = super.titleRect(forContentRect: contentRect)
let imageSize = currentImage?.size ?? .zero
let availableWidth = contentRect.width - imageEdgeInsets.right - imageSize.width - titleRect.width
return titleRect.offsetBy(dx: round(availableWidth / 2), dy: 0)
}
}
次の挿入図:

これは次のようになります。

非推奨の以前の回答
これはほとんどのシナリオで機能しますが、一部のレイアウトlayoutSubviews
ではエンドレス ループで自身を再帰的に呼び出すため、注意して使用してください。
@IBDesignable
class LeftAlignedIconButton: UIButton {
override func layoutSubviews() {
super.layoutSubviews()
contentHorizontalAlignment = .left
let availableSpace = UIEdgeInsetsInsetRect(bounds, contentEdgeInsets)
let availableWidth = availableSpace.width - imageEdgeInsets.right - (imageView?.frame.width ?? 0) - (titleLabel?.frame.width ?? 0)
titleEdgeInsets = UIEdgeInsets(top: 0, left: availableWidth / 2, bottom: 0, right: 0)
}
}
このコードは同じことを行いますが、アイコンを右端に揃えます。
@IBDesignable
class RightAlignedIconButton: UIButton {
override func layoutSubviews() {
super.layoutSubviews()
semanticContentAttribute = .forceRightToLeft
contentHorizontalAlignment = .right
let availableSpace = UIEdgeInsetsInsetRect(bounds, contentEdgeInsets)
let availableWidth = availableSpace.width - imageEdgeInsets.left - (imageView?.frame.width ?? 0) - (titleLabel?.frame.width ?? 0)
titleEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: availableWidth / 2)
}
}

正しいアラインメント バージョンが使用するsemanticContentAttribute
ため、iOS 9 以降が必要です。