0

One way to left-align a UIButton's title is to set the contentHorizontalAlignment to .left (or .leading). But this places the title flush with the left edge of the button with no margin. A common way to add some margin is to set the contentEdgeInstets.

But my button extends from once edge of the screen to the other, so I would like the left and right margins to honor the layoutMargins. These margins might change as the view is resized or the device is rotated.

enter image description here

Is there a way to set the button's insets to observe these margins? Or should I create a button from a custom view where I can use my own label and anchor it to the layoutMarginsGuide?

Ben Packard
  • 26,102
  • 25
  • 102
  • 183

3 Answers3

0

I guess you can manually set the margin of the button using titleEdgeInsets to match the inset of the Cancel Button.

Have a look at the following, the two buttons are exactly the same aside from the origin.y and the titleEdgeInsets:

let view = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
view.backgroundColor = .white

let button = UIButton(frame: CGRect(x: 40, y: 40, width: 200, height: 80))
button.setTitle("Some really long title", for: .normal)
button.backgroundColor = .red
button.setTitleColor(.black, for: .normal)

let button2 = UIButton(frame: CGRect(x: 40, y: 160, width: 200, height: 80))
button2.setTitle("Some really long title", for: .normal)
button2.backgroundColor = .red
button2.setTitleColor(.black, for: .normal)
button2.titleEdgeInsets = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)


view.addSubview(button)
view.addSubview(button2)

It gives the following result:

Button Test

Hope this helps :)

Alan S
  • 594
  • 3
  • 13
  • Yep, except hardcoding those insets means they won't respond to rotations and re-sizes which update the margins. – Ben Packard Mar 12 '20 at 14:20
  • [How about trying something like this](https://stackoverflow.com/a/8274432/10058854) to determine the inset amounts? – Alan S Mar 12 '20 at 14:25
  • Thanks, but I think if I have to monitor layout changes to update the insets I'd rather add my own label and just pin it to the `layoutMarginsGuide` instead. – Ben Packard Mar 12 '20 at 17:03
0

A subclassed button may work for you...

class RespectSuperviewMarginButton: UIButton {

    override func layoutSubviews() {
        super.layoutSubviews()
        if let sv = superview {
            contentEdgeInsets.left = sv.layoutMargins.left
        }
    }

}
DonMag
  • 69,424
  • 5
  • 50
  • 86
  • Yep, looking that way. This is simpler than what I had in mind though, thanks. Though I might just add my own label and pin it to the button's layout margins rather than look 'up' through the view hierarchy. – Ben Packard Mar 12 '20 at 17:02
0

My current best answer is: no, this is not possible without subclassing.

The subclass implementation I am currently using is simple enough:

class LayoutMarginRespectingButton: UIButton {
    override func layoutSubviews() {
        super.layoutSubviews()

        contentEdgeInsets = layoutMargins
    }
}
Ben Packard
  • 26,102
  • 25
  • 102
  • 183