How to remove the top and bottom padding of UIButton, when create it using auto layout?
Asked Answered
Z

7

26

When create UIButton with auto layout, the intrinsicContentSize always contain different top/bottom padding according to different text font size. I try to set contentEdgeInsets, but it not really works for top/bottom padding.

How to fix the padding to 0 or any constant value?

Zinn answered 7/8, 2015 at 8:29 Comment(0)
M
51

After some experimentation, it appears that if you try and set contentEdgeInsets to all zeros, the default insets are used. However, if you set them to nearly zero, it works:

button.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0.01, bottom: 0.01, right: 0)

It also appears that the values get floor'd, so you won't actually get fractional padding.

Midgut answered 6/7, 2016 at 13:31 Comment(2)
Worked for me. Thanks!Dom
The weird thing is that it transforms back to 0 in Interface Builder, thought it correctly sets to 0.01 in the .xib/.storyboard file.Ria
S
11

Updated for Swift 5

If you are wanting the button to size to its titleLabel's contents, I found that the only way to do so is by subclassing UIButton and overriding intrinsicContentSize. Hope this works for you!

class CustomButton: UIButton {
    override var intrinsicContentSize: CGSize {
        return titleLabel?.intrinsicContentSize ?? super.intrinsicContentSize
    }
}

If you need to use titleEdgeInsets, you can update your UIButton subclass like this:

class CustomButton: UIButton {
    override var titleEdgeInsets: UIEdgeInsets {
        didSet {
            invalidateIntrinsicContentSize()
        }
    }

    override var intrinsicContentSize: CGSize {
        var sizeWithInsets = titleLabel?.intrinsicContentSize ?? super.intrinsicContentSize
        sizeWithInsets.width += titleEdgeInsets.left + titleEdgeInsets.right
        sizeWithInsets.height += titleEdgeInsets.top + titleEdgeInsets.bottom
        return sizeWithInsets
    }
}
Syndic answered 12/4, 2016 at 6:31 Comment(3)
This worked really well for me. The other solution didn't work as autolayout just took the intrinsic contentSize.Kolb
This works. But, setting titleEdgeInsets (or other insets) after that doesn't seem to work anymoreEsprit
@Esprit I updated my answer to demonstrate how to support titleEdgeInsets with this solution.Syndic
O
9

CGFloat has a leastNormalMagnitude value that works nicely for this unfortunate UIKit hack.

someButton.titleEdgeInsets = UIEdgeInsets(top: .leastNormalMagnitude, left: .leastNormalMagnitude, bottom: .leastNormalMagnitude, right: .leastNormalMagnitude)
someButton.contentEdgeInsets = UIEdgeInsets(top: .leastNormalMagnitude, left: .leastNormalMagnitude, bottom: .leastNormalMagnitude, right: .leastNormalMagnitude)

Zeroing out title-edge insets alone will only zero out the leading and trailing insets. Therefore, we have to also zero out content-edge insets to zero out the top and bottom.

And for convenience:

extension UIEdgeInsets {
    init(repeating value: CGFloat) {
        self.init(top: value, left: value, bottom: value, right: value)
    }

    static let leastNormalMagnitude = UIEdgeInsets(repeating: CGFloat.leastNormalMagnitude)
}

someButton.titleEdgeInsets = .leastNormalMagnitude
someButton.contentEdgeInsets = .leastNormalMagnitude
Orwin answered 10/12, 2020 at 17:27 Comment(0)
S
8

I had issue with extra padding around button's title in iOS 15, so I've solved the problem with following code:

if #available(iOS 15.0, *) {
    detailsButton.configuration?.contentInsets = .zero

    // you could also keep padding that is more appropriate in your case
    detailsButton.configuration?.contentInsets = .init(top: 0, leading: 10,
                                                       bottom: 0, trailing: 0)
}

Also you could set style of UIButton in Attributes Inspector to Default. It'll make button's look same as it was before iOS 15

The article that helped me to get it right.

Snell answered 15/4, 2022 at 9:54 Comment(1)
This is the best solution imoWeekday
I
1

Not sure if it's because of the deprecation of contentEdgeInsets and titleEdgeInsets in iOS 15, but neither setting . contentEdgeInsets nor .titleEdgeInsets did the trick for me on iOS 15.2. Please comment below if you are facing the same issue on iOS 15+.

Eventually I ended up setting button.titleLabel constraints manually to remove paddings.

// first disable auto generated constraints
button.titleLabel?.translatesAutoresizingMaskIntoConstraints = false

// then pin titleLabel to the button
NSLayoutConstraint.activate([
            button.titleLabel!.leadingAnchor.constraint(equalTo: button.leadingAnchor),
            button.titleLabel!.trailingAnchor.constraint(equalTo: button.trailingAnchor),
            button.titleLabel!.topAnchor.constraint(equalTo: button.topAnchor),
            button.titleLabel!.bottomAnchor.constraint(equalTo: button.bottomAnchor)
        ])
Isocline answered 20/1, 2022 at 22:8 Comment(1)
Thank you! This solution worked great for me (although I also had to set button.titleLabel.textAlignment = .center). But I think you're right that the deprecation of those properties makes the other answers outdated.Libertarian
N
1

A modern way for iOS 15+

let button = UIButton()
button.configuration = {
    var config = UIButton.Configuration.plain()
    config.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)
    return config
}()
Nephelometer answered 25/2 at 14:52 Comment(1)
Please note that this general solution was posted nearly two years ago (see https://mcmap.net/q/513348/-how-to-remove-the-top-and-bottom-padding-of-uibutton-when-create-it-using-auto-layout).Parnell
B
-1

See if this works. Create the vertical constraints to the UIButton's titleLabel instead of the button itself.

Brazilein answered 12/1, 2016 at 2:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.