Autolayout - Intrinsic Size of Uibutton Does Not Include Title Insets

Autolayout - intrinsic size of UIButton does not include title insets

You can solve this without having to override any methods or set an arbitrary width constraint. You can do it all in Interface Builder as follows.

  • Intrinsic button width is derived from the title width plus the icon width plus the left and right content edge insets.

  • If a button has both an image and text, they’re centered as a group, with no padding between.

  • If you add a left content inset, it’s calculated relative to the text, not the text + icon.

  • If you set a negative left image inset, the image is pulled out to the left but the overall button width is unaffected.

  • If you set a negative left image inset, the actual layout uses half that value. So to get a -20 point left inset, you must use a -40 point left inset value in Interface Builder.

So you provide a big enough left content inset to create space for both the desired left inset and the inner padding between the icon and the text, and then shift the icon left by doubling the amount of padding you want between the icon and the text. The result is a button with equal left and right content insets, and a text and icon pair that are centered as a group, with a specific amount of padding between them.

Some example values:

// Produces a button with the layout:
// |-20-icon-10-text-20-|
// AutoLayout intrinsic width works as you'd desire.
button.contentEdgeInsets = UIEdgeInsetsMake(10, 30, 10, 20)
button.imageEdgeInsets = UIEdgeInsetsMake(0, -20, 0, 0)

UIButton width doesn't increase based on text if insets are given

Auto-layout can be a little tricky when adjusting the Title Label of a UIButton.

From Apple's docs for titleEdgeInsets:

This property is used only for positioning the title during layout. The button does not use this property to determine intrinsicContentSize and sizeThatFits(_:).

You have a couple options...

One is to subclass UIButton and override .intrinsicContentSize.

Another option, which may be better for your case, is to adjust the Content Insets instead of the Title Insets.

As you described, this button has Top / Trailing / Height constraints:

Sample Image

Sample Image

Note that the Left value for the Image Inset is a negative value. You may / probably will want to tweak the values I used.

Sample Image

UIButton sizing wrong with image and title inset

As it says in the documentation, for titleEdgeInsets: "The button does not use this property to determine intrinsicContentSize and sizeThatFits:".
So, setting the titleEdgeInsets just moves the title label, but doesn't affect the size of the button. If you want the button to have more padding around the content, set the contentEdgeInsets as well. I don't think you need to call either sizeToFit, or invalidateIntrinsicContentSize (but 'm not sure about that).

Swift button width depends on text length when adding title Insets

Storyboard buttons

Resizing button because text became larger

Please look at screenshots above. You need to set your insets and set right constraints. Autolayout does it for you.

Intrinsic size not updating when changing UIButton state

Like David Caunt pointed out in a comment, calling invalidateIntrinsicContentSize will cause autolayout to resize the button to fit it's new content.

self.selected = self.following;
[self invalidateIntrinsicContentSize];

PS. David, if you want to post your commant as an answer I will remove mine.

Adjusting the width of a UIButton depending on its title

Using Autolayout you don't have to worry about resizing the button yourself. Here's a quick layout to illustrate:

Text and info button

I've added a text button and a small round button simulating your star. In the interface builder in Xcode, I give the first button constraints for:

  • Fixed height
  • Fixed space to the left side of the view
  • Fixed space to the top side of the view

Sample Image

Then my second round button gets the following constraints:

  • Fixed width and height
  • Fixed horizontal space to the text button
  • Vertical alignment centered with the text button

Sample Image

Now when I set a long title for my button in code, you'll see that they follow each other in the way you describe:

Sample Image

Autolayout for UIButton in table view cell not working

You will have to implement your own UIButton subclass that would provide what you want. You can use following TitleAdaptingButton implementation, it overrides intrinsicContentSize to adapt to the text in title label even in vertical axis:

class TitleAdaptingButton: UIButton {

override var bounds: CGRect {
didSet {
if !oldValue.equalTo(bounds) {
invalidateIntrinsicContentSize()
}
}
}

override var intrinsicContentSize: CGSize {
get {
let labelSize = titleLabel!.sizeThatFits(CGSize(width: frame.width - (titleEdgeInsets.left + titleEdgeInsets.right), height: .greatestFiniteMagnitude))
let desiredButtonSize = CGSize(width: labelSize.width + contentEdgeInsets.left + contentEdgeInsets.right, height: labelSize.height + contentEdgeInsets.top + contentEdgeInsets.bottom)
return desiredButtonSize
}
}

override init(frame: CGRect) {
super.init(frame: frame)

self.titleLabel?.numberOfLines = 0
// if you want the text centered
// self.titleLabel?.textAlignment = .center
}

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

self.titleLabel?.numberOfLines = 0
// if you want the text centered
// self.titleLabel?.textAlignment = .center
}
}

Once you add this class into your project, just set it as a custom class for each of your buttons:

Sample Image

But remember, for the buttons to adapt, the cell has to be allowed to define its own size, so you have to use following on your tableView:

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 44 // or your better estimation


Related Topics



Leave a reply



Submit