iPhone UIButton – image position

12 Solutions Collect From Internet About “iPhone UIButton – image position”

On iOS 9 onwards, seems that a simple way to achieve this is to force the semantic of the view.

enter image description here

Or programmatically, using:

button.semanticContentAttribute = .ForceRightToLeft

My solution to this is quite simple

[button sizeToFit];
button.titleEdgeInsets = UIEdgeInsetsMake(0, -button.imageView.frame.size.width, 0, button.imageView.frame.size.width);
button.imageEdgeInsets = UIEdgeInsetsMake(0, button.titleLabel.frame.size.width, 0, -button.titleLabel.frame.size.width);

Set the imageEdgeInset and titleEdgeInset to move the components around within your image. You could also create a button using those graphics that is full size, and use that as the background image for the button (then use titleEdgeInsets to move the title around).

Raymond W’s answer is best here. Subclass UIButton with custom layoutSubviews. Extremely simple to do, here’s a layoutSubviews implementation that worked for me:

- (void)layoutSubviews
{
    // Allow default layout, then adjust image and label positions
    [super layoutSubviews];

    UIImageView *imageView = [self imageView];
    UILabel *label = [self titleLabel];

    CGRect imageFrame = imageView.frame;
    CGRect labelFrame = label.frame;

    labelFrame.origin.x = imageFrame.origin.x;
    imageFrame.origin.x = labelFrame.origin.x + CGRectGetWidth(labelFrame);

    imageView.frame = imageFrame;
    label.frame = labelFrame;
}

What about subclassing UIButton and overriding layoutSubviews?

Then post-processing the locations of self.imageView & self.titleLabel

Another simple way (that is NOT iOS 9 only) is to subclass UIButton to override these two methods

override func titleRectForContentRect(contentRect: CGRect) -> CGRect {
    var rect = super.titleRectForContentRect(contentRect)
    rect.origin.x = 0
    return rect
}

override func imageRectForContentRect(contentRect: CGRect) -> CGRect {
    var rect = super.imageRectForContentRect(contentRect)
    rect.origin.x = CGRectGetMaxX(contentRect) - CGRectGetWidth(rect)
    return rect
}

contentEdgeInsets is already taken into account by using super.

Building off the answer by @split…

The answer is fantastic, but it ignores the fact that the button may have custom image and title edge insets that are set beforehand (e.g. in storyboard).

For instance, you may want the image have some padding from the top and bottom of the container, but still move the image to the right side of the button.

I extended the concept with this method:-

- (void) moveImageToRightSide {
    [self sizeToFit];

    CGFloat titleWidth = self.titleLabel.frame.size.width;
    CGFloat imageWidth = self.imageView.frame.size.width;
    CGFloat gapWidth = self.frame.size.width - titleWidth - imageWidth;
    self.titleEdgeInsets = UIEdgeInsetsMake(self.titleEdgeInsets.top,
                                            -imageWidth + self.titleEdgeInsets.left,
                                            self.titleEdgeInsets.bottom,
                                            imageWidth - self.titleEdgeInsets.right);

    self.imageEdgeInsets = UIEdgeInsetsMake(self.imageEdgeInsets.top,
                                            titleWidth + self.imageEdgeInsets.left + gapWidth,
                                            self.imageEdgeInsets.bottom,
                                            -titleWidth + self.imageEdgeInsets.right - gapWidth);
}

In swift:

override func layoutSubviews()
{
    super.layoutSubviews()

    var imageFrame = self.imageView?.frame;
    var labelFrame = self.titleLabel?.frame;

    let inset: CGFloat = 5

    if var imageFrame = imageFrame
    {
        if var labelFrame = labelFrame
        {
            let cumulativeWidth = imageFrame.width + labelFrame.width + inset
            let excessiveWidth = self.bounds.width - cumulativeWidth
            labelFrame.origin.x = excessiveWidth / 2
            imageFrame.origin.x = labelFrame.origin.x + labelFrame.width + inset

            self.imageView?.frame = imageFrame
            self.titleLabel?.frame = labelFrame
        }
    }
}
// Get the size of the text and image
CGSize buttonLabelSize = [[self.button titleForState:UIControlStateNormal] sizeWithFont:self.button.titleLabel.font];
CGSize buttonImageSize = [[self.button imageForState:UIControlStateNormal] size];

// You can do this line in the xib too:
self.button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;

// Adjust Edge Insets according to the above measurement. The +2 adds a little space 
self.button.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, -(buttonLabelSize.width+2));
self.button.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, buttonImageSize.width+2);

This creates a right-aligned button, like so:

[           button label (>)]

The button doesn’t adjust it’s width according to the context, so space will appear on the left of the label. You could solve this by calculating the button’s frame width from the buttonLabelSize.width and the buttonImageSize.width.

button.semanticContentAttribute = UISemanticContentAttributeForceRightToLeft;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;

This solution works iOS 7 and above

Just subclass UIButton

@interface UIButton (Image)

- (void)swapTextWithImage;

@end

@implementation UIButton (Image)

- (void)swapTextWithImage {
   const CGFloat kDefaultPadding = 6.0f;
   CGSize buttonSize = [self.titleLabel.text sizeWithAttributes:@{
                                                               NSFontAttributeName:self.titleLabel.font
                                                               }];

   self.titleEdgeInsets = UIEdgeInsetsMake(0, -self.imageView.frame.size.width, 0, self.imageView.frame.size.width);
   self.imageEdgeInsets = UIEdgeInsetsMake(0, buttonSize.width + kDefaultPadding, 0, -buttonSize.width); 
}

@end

Usage (Somewhere in your class):

[self.myButton setTitle:@"Any text" forState:UIControlStateNormal];
[self.myButton swapTextWithImage];

Building on previous answers. If you want to have a margin between the icon and the title of the button, the code has to change a little to prevent floating of the label and icon above the bounds of intrinsically sized buttons.

let margin = CGFloat(4.0)
button.titleEdgeInsets = UIEdgeInsetsMake(0, -button.imageView.frame.size.width, 0, button.imageView.frame.size.width);
button.imageEdgeInsets = UIEdgeInsetsMake(0, button.titleLabel.frame.size.width, 0, -button.titleLabel.frame.size.width)
button.contentEdgeInsets = UIEdgeInsetsMake(0, margin, 0, margin)

The last code line is important for the intrinsically content size calculation for auto layout.