Uibutton: How to Center an Image and a Text Using Imageedgeinsets and Titleedgeinsets

UIButton: how to center an image and a text using imageEdgeInsets and titleEdgeInsets?

For what it's worth, here's a general solution to positioning the image centered above the text without using any magic numbers. Note that the following code is outdated and you should probably use one of the updated versions below:

// the space between the image and text
CGFloat spacing = 6.0;

// lower the text and push it left so it appears centered
// below the image
CGSize imageSize = button.imageView.frame.size;
button.titleEdgeInsets = UIEdgeInsetsMake(
0.0, - imageSize.width, - (imageSize.height + spacing), 0.0);

// raise the image and push it right so it appears centered
// above the text
CGSize titleSize = button.titleLabel.frame.size;
button.imageEdgeInsets = UIEdgeInsetsMake(
- (titleSize.height + spacing), 0.0, 0.0, - titleSize.width);

The following version contains changes to support iOS 7+ that have been recommended in comments below. I haven't tested this code myself, so I'm not sure how well it works or whether it would break if used under previous versions of iOS.

// the space between the image and text
CGFloat spacing = 6.0;

// lower the text and push it left so it appears centered
// below the image
CGSize imageSize = button.imageView.image.size;
button.titleEdgeInsets = UIEdgeInsetsMake(
0.0, - imageSize.width, - (imageSize.height + spacing), 0.0);

// raise the image and push it right so it appears centered
// above the text
CGSize titleSize = [button.titleLabel.text sizeWithAttributes:@{NSFontAttributeName: button.titleLabel.font}];
button.imageEdgeInsets = UIEdgeInsetsMake(
- (titleSize.height + spacing), 0.0, 0.0, - titleSize.width);

// increase the content height to avoid clipping
CGFloat edgeOffset = fabsf(titleSize.height - imageSize.height) / 2.0;
button.contentEdgeInsets = UIEdgeInsetsMake(edgeOffset, 0.0, edgeOffset, 0.0);

Swift 5.0 version

extension UIButton {
func alignVertical(spacing: CGFloat = 6.0) {
guard let imageSize = imageView?.image?.size,
let text = titleLabel?.text,
let font = titleLabel?.font
else { return }

titleEdgeInsets = UIEdgeInsets(
top: 0.0,
left: -imageSize.width,
bottom: -(imageSize.height + spacing),
right: 0.0
)

let titleSize = text.size(withAttributes: [.font: font])
imageEdgeInsets = UIEdgeInsets(
top: -(titleSize.height + spacing),
left: 0.0,
bottom: 0.0,
right: -titleSize.width
)

let edgeOffset = abs(titleSize.height - imageSize.height) / 2.0
contentEdgeInsets = UIEdgeInsets(
top: edgeOffset,
left: 0.0,
bottom: edgeOffset,
right: 0.0
)
}
}

Aligning text and image on UIButton with imageEdgeInsets and titleEdgeInsets

I agree the documentation on imageEdgeInsets and titleEdgeInsets should be better, but I figured out how to get the correct positioning without resorting to trial and error.

The general idea is here at this question, but that was if you wanted both text and image centered. We don't want the image and text to be centered individually, we want the image and the text to be centered together as a single entity. This is in fact what UIButton already does so we simply need to adjust the spacing.

CGFloat spacing = 10; // the amount of spacing to appear between image and title
tabBtn.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, spacing);
tabBtn.titleEdgeInsets = UIEdgeInsetsMake(0, spacing, 0, 0);

I also turned this into a category for UIButton so it will be easy to use:

UIButton+Position.h

@interface UIButton(ImageTitleCentering)

-(void) centerButtonAndImageWithSpacing:(CGFloat)spacing;

@end

UIButton+Position.m

@implementation UIButton(ImageTitleCentering)

-(void) centerButtonAndImageWithSpacing:(CGFloat)spacing {
self.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, spacing);
self.titleEdgeInsets = UIEdgeInsetsMake(0, spacing, 0, 0);
}

@end

So now all I have to do is:

[button centerButtonAndImageWithSpacing:10];

And I get what I need every time. No more messing with the edge insets manually.

EDIT: Swapping Image and Text

In response to @Javal in comments

Using this same mechanism, we can swap the image and the text. To accomplish the swap, simply use a negative spacing but also include the width of the text and the image. This will require frames to be known and layout performed already.

[self.view layoutIfNeeded];
CGFloat flippedSpacing = -(desiredSpacing + button.currentImage.size.width + button.titleLabel.frame.size.width);
[button centerButtonAndImageWithSpacing:flippedSpacing];

Of course you will probably want to make a nice method for this, potentially adding a second category method, this is left as an exercise to the reader.

UIButton align image left and center text

All the properties you mentioned above can be set in the init of the UIButton there is absolutely no need to set them in layoutSubviews or willMove(toWindow.
layoutSubviews will be called multiple times so setting these properties again n agin in here makes no sense. willMove(toWindow will be called when button is added to some view and button is loaded but you dont have to wait till then to set these properties. Because you already have a subclass of button, so I would suggest doing

class SomeButton: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
self.titleEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
self.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
self.contentHorizontalAlignment = .center
}

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

By the way creating a subclass of UIButton is not recommended, so if you wanna simply assign these properties to your button you can rather have a extension to UIButton

extension UIButton {
func applyStyle() {
self.titleEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
self.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
self.contentHorizontalAlignment = .center
}
}

EDIT:

Is this what you want??

Sample Image

Sample Image

No matter what the text is, text is always in centre and image is to its left with 10 pixel padding

EDIT 2:

As OP has confirmed that, he wants the button to be styled as showed in images above, posting the code to achieve the same

class SomeButton: UIButton {
var titleFont: UIFont! = nil
var textSize: CGFloat = 0
let imageWidth: CGFloat = 20
let buttonHeight: CGFloat = 30

override init(frame: CGRect) {
super.init(frame: frame)
self.titleFont = titleLabel!.font
self.setTitle("here", for: .normal)
self.setTitleColor(UIColor.red, for: .normal)
self.setImage(UIImage(named: "hand"), for: .normal)
self.backgroundColor = UIColor.green
}

override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
if let string = self.title(for: .normal) {
textSize = string.widthOfString(usingFont: self.titleFont)
//30 because imageWidth + 10 padding
return CGRect(origin: CGPoint(x: 30, y: 0), size: CGSize(width: textSize + 30, height: buttonHeight))
}
return CGRect.zero
}

override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
return CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: imageWidth, height: buttonHeight))
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}

override var intrinsicContentSize: CGSize {
//60 because you need eauql padding on both side 30 + 30 = 60
return CGSize(width: textSize + 60, height: buttonHeight)
}
}

extension String {

func widthOfString(usingFont font: UIFont) -> CGFloat {
let fontAttributes = [NSAttributedString.Key.font: font]
let size = self.size(withAttributes: fontAttributes)
return size.width
}
}

Hope it helps

Align image at the right corner of UIButton irrespective of text length

Use override method of UIButton and manage your title and image frame.

Here is UIButton subclass.

class ButtonIconRight: UIButton {
override func imageRect(forContentRect contentRect:CGRect) -> CGRect {
var imageFrame = super.imageRect(forContentRect: contentRect)
imageFrame.origin.x = self.bounds.width - imageFrame.width
return imageFrame
}

override func titleRect(forContentRect contentRect:CGRect) -> CGRect {
var titleFrame = super.titleRect(forContentRect: contentRect)
if (self.currentImage != nil) {
titleFrame.origin.x = 0
}
return titleFrame
}
}

Sample Image

The space between title and text on UIButton is not correct when adjusting titleEdgeInsets and imageEdgeInsets

You Didn't set imageEdgeInsets like this :

rightButton.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 10)

So total Code is here :

leftButton.contentHorizontalAlignment = .left
leftButton.imageView?.backgroundColor = .red
leftButton.titleLabel?.backgroundColor = .gray
leftButton.titleEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 0)

rightButton.contentHorizontalAlignment = .center
rightButton.imageView?.backgroundColor = .red
rightButton.titleLabel?.backgroundColor = .gray
rightButton.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 10)
rightButton.titleEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 0)

Reason:
Actually you need to set imageEdgeInsets both time left alignment or center alignment
But when its left alignment image there is no space to set Insets at the right side.

Seet this code :

leftButton.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 100)

Here is also no space .

So home you get some idea how insets work :

For your more Help :

Click here

ios - Left Align Image and Place Text in Center of UIButton

@Rohan The issue is let margin = 30 - image.size.width / 2. You are using image width to find out the margin.The Images (facebook and google) size are different(I am assuming). So according to your code, label left margin must change with image width. So if you want to achieve You have to keep both image size similar according to your code.

Custom UIButton imageEdgeInsets/titleEdgeInsets not working

Try changing button style to default via buttons attribute inspector.

Sample Image



Related Topics



Leave a reply



Submit