Label under image in UIButton Label under image in UIButton ios ios

Label under image in UIButton


Or you can just use this category:

ObjC

@interface UIButton (VerticalLayout)- (void)centerVerticallyWithPadding:(float)padding;- (void)centerVertically;@end@implementation UIButton (VerticalLayout)- (void)centerVerticallyWithPadding:(float)padding {    CGSize imageSize = self.imageView.frame.size;    CGSize titleSize = self.titleLabel.frame.size;    CGFloat totalHeight = (imageSize.height + titleSize.height + padding);        self.imageEdgeInsets = UIEdgeInsetsMake(- (totalHeight - imageSize.height),                                            0.0f,                                            0.0f,                                            - titleSize.width);        self.titleEdgeInsets = UIEdgeInsetsMake(0.0f,                                            - imageSize.width,                                            - (totalHeight - titleSize.height),                                            0.0f);        self.contentEdgeInsets = UIEdgeInsetsMake(0.0f,                                              0.0f,                                              titleSize.height,                                              0.0f);}- (void)centerVertically {    const CGFloat kDefaultPadding = 6.0f;    [self centerVerticallyWithPadding:kDefaultPadding];}@end

Swift extension

extension UIButton {        func centerVertically(padding: CGFloat = 6.0) {        guard            let imageViewSize = self.imageView?.frame.size,            let titleLabelSize = self.titleLabel?.frame.size else {            return        }                let totalHeight = imageViewSize.height + titleLabelSize.height + padding                self.imageEdgeInsets = UIEdgeInsets(            top: -(totalHeight - imageViewSize.height),            left: 0.0,            bottom: 0.0,            right: -titleLabelSize.width        )                self.titleEdgeInsets = UIEdgeInsets(            top: 0.0,            left: -imageViewSize.width,            bottom: -(totalHeight - titleLabelSize.height),            right: 0.0        )                self.contentEdgeInsets = UIEdgeInsets(            top: 0.0,            left: 0.0,            bottom: titleLabelSize.height,            right: 0.0        )    }    }

Suggestion:If button height is less than totalHeight, then image will draw outside borders.

imageEdgeInset.top should be:

max(0, -(totalHeight - imageViewSize.height))


In Xcode, you can simply set the Edge Title Left Inset to negative the width of the image. This will display the label in the center of the image.

To get the label to display below the image (sorta like the app buttons), you may need to set the Edge Title Top Inset to some positive number.

Edit: Here is some code to achieve that without using Interface Builder:

/// This will move the TitleLabel text of a UIButton to below it's Image and Centered./// Note: No point in calling this function before autolayout lays things out./// - Parameter padding: Some extra padding to be appliedfunc centerVertically(padding: CGFloat = 18.0) {    // No point in doing anything if we don't have an imageView size    guard let imageFrame = imageView?.frame else { return }    titleLabel?.numberOfLines = 0    titleEdgeInsets.left = -(imageFrame.width + padding)    titleEdgeInsets.top = (imageFrame.height + padding)}

Please note this won't work if you're using autolayout and the button didn't get layed out in the screen yet via constraints.


This is a simple centered title button implemented in Swift by overriding titleRect(forContentRect:) and imageRect(forContentRect:). It also implements intrinsicContentSize for use with AutoLayout.

import UIKitclass CenteredButton: UIButton{    override func titleRect(forContentRect contentRect: CGRect) -> CGRect {        let rect = super.titleRect(forContentRect: contentRect)        return CGRect(x: 0, y: contentRect.height - rect.height + 5,            width: contentRect.width, height: rect.height)    }    override func imageRect(forContentRect contentRect: CGRect) -> CGRect {        let rect = super.imageRect(forContentRect: contentRect)        let titleRect = self.titleRect(forContentRect: contentRect)        return CGRect(x: contentRect.width/2.0 - rect.width/2.0,            y: (contentRect.height - titleRect.height)/2.0 - rect.height/2.0,            width: rect.width, height: rect.height)    }    override var intrinsicContentSize: CGSize {        let size = super.intrinsicContentSize        if let image = imageView?.image {            var labelHeight: CGFloat = 0.0            if let size = titleLabel?.sizeThatFits(CGSize(width: self.contentRect(forBounds: self.bounds).width, height: CGFloat.greatestFiniteMagnitude)) {                labelHeight = size.height            }            return CGSize(width: size.width, height: image.size.height + labelHeight + 5)        }        return size    }    override init(frame: CGRect) {        super.init(frame: frame)        centerTitleLabel()    }    required init?(coder aDecoder: NSCoder) {        super.init(coder: aDecoder)        centerTitleLabel()    }    private func centerTitleLabel() {        self.titleLabel?.textAlignment = .center    }}