Left-align image and center text on UIButton

IosUiimageUibutton

Ios Problem Overview


I've seen posts regarding right alignment but I can't get left-alignment to work. I want the button to take up the width of the screen, with the image on the left and the title/text in the center.

This does not work (at least reliably):

    button.titleLabel.textAlignment = UITextAlignmentCenter;
    [button setImageEdgeInsets:UIEdgeInsetsMake(0, -60.0, 0, 0)];
    button.frame = CGRectMake((self.view.frame.size.width - w ) / 2, self.view.frame.size.height - 140.0,  self.view.frame.size.width - 10.0, 40.0);

Ios Solutions


Solution 1 - Ios

This solution works with Swift 3 and respects original content and image edge insets while keeping the title label always centered in the available space, which makes much easier adjusting margins.

It overrides titleRect(forContentRect:) method and returns the correct frame:

@IBDesignable
class LeftAlignedIconButton: UIButton {
    override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
        let titleRect = super.titleRect(forContentRect: contentRect)
        let imageSize = currentImage?.size ?? .zero
        let availableWidth = contentRect.width - imageEdgeInsets.right - imageSize.width - titleRect.width
        return titleRect.offsetBy(dx: round(availableWidth / 2), dy: 0)
    }
}

The following insets:

enter image description here

Would result in this:

enter image description here


Deprecated previous answer

This works in most scenarios, but some layouts cause layoutSubviews to recursively call itself in an endless loop, so use with caution.

@IBDesignable
class LeftAlignedIconButton: UIButton {
    override func layoutSubviews() {
        super.layoutSubviews()
        contentHorizontalAlignment = .left
        let availableSpace = UIEdgeInsetsInsetRect(bounds, contentEdgeInsets)
        let availableWidth = availableSpace.width - imageEdgeInsets.right - (imageView?.frame.width ?? 0) - (titleLabel?.frame.width ?? 0)
        titleEdgeInsets = UIEdgeInsets(top: 0, left: availableWidth / 2, bottom: 0, right: 0)
    }
}

This code would do the same but aligning the icon to the right edge:

@IBDesignable
class RightAlignedIconButton: UIButton {
    override func layoutSubviews() {
        super.layoutSubviews()
        semanticContentAttribute = .forceRightToLeft
        contentHorizontalAlignment = .right
        let availableSpace = UIEdgeInsetsInsetRect(bounds, contentEdgeInsets)
        let availableWidth = availableSpace.width - imageEdgeInsets.left - (imageView?.frame.width ?? 0) - (titleLabel?.frame.width ?? 0)
        titleEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: availableWidth / 2)
    }
}

enter image description here

The right allignment version uses semanticContentAttribute so it requires iOS 9+.

Solution 2 - Ios

In my end, I did this using UIEdgeInsetsMake which the left corner is calculated to make it to the center. I am not sure if there's something really you can make the text at aligned at the center but this works for me. Make sure that you set your left corner to your desired position by calculating the width. e.g. UIEdgeInsetsMake(0.0f, 42.0f, 0.0f, 0.0f)

UIButton *scanBarCodeButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
scanBarCodeButton.frame = CGRectMake(center, 10.0f, fieldWidth, 40.0f);
[scanBarCodeButton setImage:[UIImage imageNamed:@"BarCodeIcon.png"] forState:UIControlStateNormal];
[scanBarCodeButton setTitle:@"Scan the Barcode" forState:UIControlStateNormal];
scanBarCodeButton.titleEdgeInsets = UIEdgeInsetsMake(0.0f, 42.0f, 0.0f, 0.0f);
[scanBarCodeButton setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
[scanBarCodeButton addTarget:self action:@selector(scanBarCode:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:scanBarCodeButton];

The output looks like,

centered text with image

In Swift:

var scanBarCodeButton: UIButton = UIButton(type: .roundedRect)
scanBarCodeButton.frame = CGRectMake(center, 10.0, fieldWidth, 40.0)
scanBarCodeButton.setImage(UIImage(named: "BarCodeIcon.png"), for: UIControlStateNormal)
scanBarCodeButton.setTitle("Scan the Barcode", for: UIControlStateNormal)
scanBarCodeButton.titleEdgeInsets = UIEdgeInsetsMake(0.0, 42.0, 0.0, 0.0)
scanBarCodeButton.contentHorizontalAlignment = .left
scanBarCodeButton.addTarget(self, action: "scanBarCode:", for: UIControlEventTouchUpInside)
self.view.addSubview(scanBarCodeButton)

Solution 3 - Ios

For Swift 4.0, here's an extension that works-

extension UIButton {

  func leftImage(image: UIImage, renderMode: UIImage.RenderingMode) {
       self.setImage(image.withRenderingMode(renderMode), for: .normal)
       self.imageEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 0)
       self.titleEdgeInsets.left = (self.frame.width/2) - (self.titleLabel?.frame.width ?? 0)
       self.contentHorizontalAlignment = .left
       self.imageView?.contentMode = .scaleAspectFit
   }
    
    func rightImage(image: UIImage, renderMode: UIImageRenderingMode){
        self.setImage(image.withRenderingMode(renderMode), for: .normal)
        self.imageEdgeInsets = UIEdgeInsets(top: 0, left:image.size.width / 2, bottom: 0, right: 0)
        self.contentHorizontalAlignment = .right
        self.imageView?.contentMode = .scaleAspectFit
    }
}

Usage:

myButton.rightImage(image: UIImage(named: "image_name")!, renderMode: .alwaysOriginal)
myButton.leftImage(image: UIImage(named: "image_name")!, renderMode: .alwaysOriginal)

renderMode can be .alwaysTemplate or .alwaysOriginal. Also, myButton should be a custom type UIButton.

This extension's leftImage and rightImage can also be used in UIButton in UIBarButtonItem for UINavigationBar(Note: as of iOS 11, the navigation bar follows autolayout so you will need to add width/height constraints to the UIBarButtonItem). For usage on Navigation Bar, make sure you follow the Apple recommended @2x and @3x image sizes (i.e. 50x50, 75x75) and to have better accessibility on iPhone 6, 7 , 8, 6s, 7s, 8s, the Plus variants and iPhone x the width and height of the UIBarButton could be height - 25 and width - 55 (or whatever your app requires, these numbers are some basic numbers that should work for most cases).


UPDATE: In Swift 4.2, UIImageRenderingMode has been renamed to UIImage.RenderingMode

extension UIButton {
    func leftImage(image: UIImage, renderMode: UIImage.RenderingMode) {
        self.setImage(image.withRenderingMode(renderMode), for: .normal)
        self.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: image.size.width / 2)
        self.contentHorizontalAlignment = .left
        self.imageView?.contentMode = .scaleAspectFit
    }
    
    func rightImage(image: UIImage, renderMode: UIImage.RenderingMode){
        self.setImage(image.withRenderingMode(renderMode), for: .normal)
        self.imageEdgeInsets = UIEdgeInsets(top: 0, left:image.size.width / 2, bottom: 0, right: 0)
        self.contentHorizontalAlignment = .right
        self.imageView?.contentMode = .scaleAspectFit
    }
}

Solution 4 - Ios

I've tried almost every solution above and none of them worked as I expected (I had two buttons each with different tittle and with different image width). So I have written my own extension for UIButton, which works flawlessly with different image widths as well as with different titles.

extension UIButton {
    func moveImageLeftTextCenter(imagePadding: CGFloat = 30.0, titlePadding: CGFloat = 0.0, minImageTitleDistance: CGFloat = 10.0){
    guard let imageViewWidth = imageView?.frame.width else{return}
    guard let titleLabelWidth = titleLabel?.intrinsicContentSize.width else{return}
    contentHorizontalAlignment = .left
    
    let imageLeftInset = imagePadding - imageViewWidth / 2
    var titleLeftInset = (bounds.width - titleLabelWidth) / 2 - imageViewWidth + titlePadding
    
    if titleLeftInset - imageLeftInset < minImageTitleDistance{
        titleLeftInset = imageLeftInset + minImageTitleDistance
    }
    
    imageEdgeInsets = UIEdgeInsets(top: 0.0, left: imageLeftInset, bottom: 0.0, right: 0.0)
    titleEdgeInsets = UIEdgeInsets(top: 0.0, left: titleLeftInset, bottom: 0.0, right: 0.0)
    }
}

Usage: myButton.moveImageLeftTextCenter()

Solution 5 - Ios

As I think, the good solution must be useful for any text, without hardcoded values for insets (it's about the solution provided by toytoy). I use the code similar to this:

NSString *sometitle = @"blabla button title";
NSString *someimage = @"blablaimage";
UIImage *image = [[UIImage imageNamed:someimage];
int buttonWidth = A;
int buttonHeight = B;
int imageWidth =image.size.width;
int imageHeight = image.size.height;
int titleWidth = buttonWidth - imageWidth;

// create button and set image and title
buttonView = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, buttonWidth, buttonHeight)];
[buttonView setImage:image forState:UIControlStateNormal];
[buttonView setTitle:sometitle forState:UIControlStateNormal];

// make button all content to be left aligned
[buttonView setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];

// set title font 
[buttonView.titleLabel setFont:[UIFont fontWithName:@"HelveticaNeue" size:14]];

// calculate font text width with selected font
CGSize stringBoundingBox = [number sizeWithFont:[buttonView.titleLabel font]];

// make title inset with some value from left 
// it place the title right on the center of space for the title
int titleLeft = (titleWidth - stringBoundingBox.width) / 2;
[buttonView setTitleEdgeInsets:UIEdgeInsetsMake(0, titleLeft, 0, 0)];

After the string with stringBoundingBox init I also add some strings like this:

if (stringBoundingBox.width > titleWidth)
{
    [_backgroundView.titleLabel setFont:[UIFont fontWithName:@"HelveticaNeue" size:13]];
    stringBoundingBox = [number sizeWithFont:[_backgroundView.titleLabel font]];
}
if (stringBoundingBox.width > titleWidth)
{
    [_backgroundView.titleLabel setFont:[UIFont fontWithName:@"HelveticaNeue" size:12]];
    stringBoundingBox = [number sizeWithFont:[_backgroundView.titleLabel font]];
}

it allow to me set the titles longer than available space, by selecting some smaller fonts. I make this because of another way for this:

[buttonView.titleLabel setAdjustsFontSizeToFitWidth:YES];

works not very good, looks like it take the font size for 3-4 points smaller at one step, so some not so long lines become too smaller, than it must to be.

This code allow us to place any text in button title space exactly in center.

Solution 6 - Ios

[self.button setImage:[UIImage imageNamed:@"image.png"] forState:UIControlStateNormal];

[self.button setTitleEdgeInsets:UIEdgeInsetsMake(0.0, self.button.center.x/2 , 0.0, 0.0)];

[self.button setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];

Let me know if it is not working.

> My output enter image description here

Solution 7 - Ios

I wrote an UIButton extension.

extension UIButton {

  /// Add image on left view
  func leftImage(image: UIImage) {
    self.setImage(image, for: .normal)
    self.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: image.size.width)
  }
}

And you could use like this :

yourButton.leftImage(image: yourImage)

Voila !

Solution 8 - Ios

Create your button and set the text alignment to center, then add:

UIImage *image = [UIImage imageNamed:@"..."];
CGSize imageSize = image.size;
CGFloat offsetY = floor((self.layer.bounds.size.height - imageSize.height) / 2.0);

CALayer *imageLayer = [CALayer layer];
imageLayer.contents = (__bridge id) image.CGImage;
imageLayer.contentsGravity = kCAGravityBottom;
imageLayer.contentsScale = [UIScreen mainScreen].scale;
imageLayer.frame = CGRectMake(offsetY, offsetY, imageSize.width, imageSize.height);
[self.layer addSublayer:imageLayer];

Solution 9 - Ios

Tried most of the answers with no luck. I was getting a blue image most of the time, or the title was not center. Used code from a few of the answers and wrote this extension, works like a charm.

Swift 4.2:

import UIKit

extension UIButton {
    func moveImageLeftTextCenter(image : UIImage, imagePadding: CGFloat, renderingMode: UIImage.RenderingMode){
        self.setImage(image.withRenderingMode(renderingMode), for: .normal)
        guard let imageViewWidth = self.imageView?.frame.width else{return}
        guard let titleLabelWidth = self.titleLabel?.intrinsicContentSize.width else{return}
        self.contentHorizontalAlignment = .left
        let imageLeft = imagePadding - imageViewWidth / 2
        let titleLeft = (bounds.width - titleLabelWidth) / 2 - imageViewWidth
        imageEdgeInsets = UIEdgeInsets(top: 0.0, left: imageLeft, bottom: 0.0, right: 0.0)
        titleEdgeInsets = UIEdgeInsets(top: 0.0, left: titleLeft , bottom: 0.0, right: 0.0)
    }
}

Hope it helps for some!

Solution 10 - Ios

This works well for me, for several buttons, with different image width and different title length :

Subclass UIButton, and add the following method:

override func layoutSubviews() {
    super.layoutSubviews()
            
    if let image = imageView?.image {

        let margin = 30 - image.size.width / 2
        let titleRect = titleRectForContentRect(bounds)
        let titleOffset = (bounds.width - titleRect.width - image.size.width - margin) / 2

        
        contentHorizontalAlignment = UIControlContentHorizontalAlignment.Left
            imageEdgeInsets = UIEdgeInsetsMake(0, margin, 0, 0)
            titleEdgeInsets = UIEdgeInsetsMake(0, (bounds.width - titleRect.width -  image.size.width - margin) / 2, 0, 0)
    }
    
}

Solution 11 - Ios

  1. button.frame = self.view.bounds;

  2. setImageEdgeInsets with negative values, when your button fills the screen, is madness. Reconsider what you're trying to do here?

  3. UITextAlignmentCenter is now NSTextAlignmentCenter

  4. button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;

Solution 12 - Ios

I wrote an UIButton extension in swift -

extension UIButton {

func setLeftImage(imageName:String, padding:CGFloat) {
        //Set left image
        let image = UIImage(named: imageName)
        self.setImage(image, forState: .Normal)
        
        //Calculate and set image inset to keep it left aligned
        let imageWidth = image?.size.width
        let textWidth = self.titleLabel?.intrinsicContentSize().width
        let buttonWidth = CGRectGetWidth(self.bounds)
        
        let padding:CGFloat = 30.0
        let rightInset = buttonWidth - imageWidth!  - textWidth! - padding
        
        self.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: rightInset)
    }
}

I would style my button text any way i want, keep it in center alignment. Then I would call this method on my button like -

myButton.setLeftImage("image_name", 30.0)

This would result in my image to be left aligned with some padding from the left border.

Solution 13 - Ios

I see a lot of solutions here that focus on setting the icon to the left. I think it's way easier to just add a UIImageView, align the left sides of the button and the image and center them together as well. Then you can play a bit with the offset to make it look nice.

No code, all in Interface Builder.

Solution 14 - Ios

One trick is to:

  1. Override titleRectForContentRect to make the button's titleLabel's frame equal to the button's bounds

  2. Set the titleLabel's textAlignment to .Center

  3. override imageRectForContentRect to specify the origin.x of the button's imageView

     import UIKit
     
     class ButtonWithLeftAlignedImageAndCenteredText: UIButton {
     
         override init(frame: CGRect) {
             super.init(frame: frame)
        
             titleLabel?.textAlignment = .Center
         }
     
         override func imageRectForContentRect(contentRect: CGRect) -> CGRect {
             var imageFrame = super.imageRectForContentRect(contentRect)
             imageFrame.origin.x = 20 //offset from left edge
             return imageFrame
         }
     
         override func titleRectForContentRect(contentRect:CGRect) -> CGRect {
             var titleFrame = super.titleRectForContentRect(contentRect)
             titleFrame = self.bounds
             return titleFrame
         }
     
     
         required init?(coder aDecoder: NSCoder) {
             fatalError("init(coder:) has not been implemented")
         }
     }
    

Solution 15 - Ios

I know this answer is kinda late. But I have a very simple solution for folks who want to add an image, using UIImageView, in the left side of an UIButton with centered text. All programmatically

class RandomVC: UIViewController{

    var imageDemo: UIImageView = {
    let img = UIImageView()
    img.translatesAutoresizingMaskIntoConstraints = false
    img.image = UIImage(named: "someImgFromAssets")
    return img
    }()

    lazy var someButton: UIButton = { //lazy var: so button can have access to self class
    let button = UIButton(type: .system)
    button.setTitle("This is your title", for: UIControlState.normal)
    button.translatesAutoresizingMaskIntoConstraints = false 
    button.setTitleColor(UIColor.white, for: UIControlState.normal)
    button.addTarget(self, action: #selector(handleButtonClick), for: .touchUpInside) //make sure you write function "handleButtonClick" inside your class
    button.titleLabel?.textAlignment = .center
    return button
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubView(someButton)
        someButton.addSubview(imageDemo)
        imageDemo.centerYAnchor.constraint(equalTo: someButton.centerYAnchor).isActive = true
        imageDemo.leftAnchor.constraint(equalTo: someButton.leftAnchor, constant: 10).isActive = true
        imageDemo.heightAnchor.constraint(equalToConstant: 25).isActive = true
        imageDemo.widthAnchor.constraint(equalToConstant: 25).isActive = true
    }

}
   

Solution 16 - Ios

Following extension works for me in Swift 4.2

func leftImage(image: UIImage, padding: CGFloat, renderMode: UIImage.RenderingMode) {
    self.setImage(image.withRenderingMode(renderMode), for: .normal)
    contentHorizontalAlignment = .left
    let availableSpace = bounds.inset(by: contentEdgeInsets)
    let availableWidth = availableSpace.width - imageEdgeInsets.right - (imageView?.frame.width ?? 0) - (titleLabel?.frame.width ?? 0)
    titleEdgeInsets = UIEdgeInsets(top: 0, left: availableWidth / 2, bottom: 0, right: 0)
    imageEdgeInsets = UIEdgeInsets(top: 0, left: padding, bottom: 0, right: 0)
}

func rightImage(image: UIImage, padding: CGFloat, renderMode: UIImage.RenderingMode){
    self.setImage(image.withRenderingMode(renderMode), for: .normal)
    semanticContentAttribute = .forceRightToLeft
    contentHorizontalAlignment = .right
    let availableSpace = bounds.inset(by: contentEdgeInsets)
    let availableWidth = availableSpace.width - imageEdgeInsets.left - (imageView?.frame.width ?? 0) - (titleLabel?.frame.width ?? 0)
    titleEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: availableWidth / 2)
    imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: padding)
}

Solution 17 - Ios

My SWIFT 5.2 solution.

You have to subclass UIButton class. No need to change the content horizontal alignment like others did in other answers, keep it to "center" (.center). The title will be automatically centered, while the override of imageRect() will do the trick for the image.

The first thing you have to do is to assign CustomButton class to your button in storyboard's Identity Inspector section. Then, you can switch "alignImageToLeft" to ON or OFF on Attribute Inspector's section (default will be OFF).

class CustomButton : UIButton {

    @IBInspectable var alignImageToLeft : Bool = false

    override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
        if(alignImageToLeft){
            let imageRect = super.imageRect(forContentRect: contentRect)
            let offset = contentRect.minX - imageRect.minX
            return imageRect.offsetBy(dx: offset, dy: 0.0)
        }
        return super.imageRect(forContentRect: contentRect)
    }
}

Solution 18 - Ios

You can use below code to Left-align image on UIButton :-

Step 1:

//create your UIButton
UIButton *post_bNeeds_BTN= [UIButton buttonWithType:UIButtonTypeRoundedRect];
post_bNeeds_BTN.frame= CGRectMake(160 ,5 ,150 ,40);
[post_bNeeds_BTN addTarget:self action:@selector(post_Buying_Needs_BTN_Pressed:) forControlEvents:UIControlEventTouchUpInside];
[post_bNeeds_BTN setBackgroundColor:[UIColor colorWithRed:243/255.0 green:131/255.0 blue:26/255.0 alpha:1.0f]];//230
[self.view addSubview:post_bNeeds_BTN];
post_bNeeds_BTN.autoresizingMask= UIViewAutoresizingFlexibleWidth;

Step 2:

//Add UIImageView on right side the button
UIImageView *bNeedsIVw= [[UIImageView alloc] initWithFrame:CGRectMake(5,5,30,30)];
bNeedsIVw.image= [UIImage imageNamed:@"postRequir_30.png"];
bNeedsIVw.image= [bNeedsIVw.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
bNeedsIVw.tintColor= [UIColor whiteColor];
[post_bNeeds_BTN addSubview:bNeedsIVw];

Step 3:

//also set UILable on UIButton
UILabel *bNeedsLbl= [[UILabel alloc] initWithFrame:CGRectMake(40 ,0 ,post_Prod_BTN.frame.size.width-40 ,post_Prod_BTN.frame.size.height)];
bNeedsLbl.text= @"Requirements";
bNeedsLbl.font= [UIFont systemFontOfSize:16];
bNeedsLbl.textColor= [UIColor whiteColor];
bNeedsLbl.textAlignment= NSTextAlignmentLeft;
[post_bNeeds_BTN addSubview:bNeedsLbl];

Step 4:

-(void)post_Buying_Needs_BTN_Pressed:(id)sender{
    //write your code action here,,
}

thanks,

Solution 19 - Ios

this code makes your button image to align left, and title label moves to center of button. b is button :)

b.contentHorizontalAlignment = .Left
let left = (b.frameWidth() - b.titleLabel!.frameWidth()) / 2 - CGRectGetMaxX(b.imageView!.frame)
b.titleEdgeInsets = UIEdgeInsetsMake(0, left, 0, 0)

Solution 20 - Ios

This solution can be applied using an extension. No need of subclassing.

Warning: this must be called every time the text/image is updated.

let width = frame.width
guard let imageWidth = imageView?.frame.width, let labelWidth = titleLabel?.frame.width else {
      return
}
titleEdgeInsets = UIEdgeInsets(top: 0, left: (width - labelWidth)/2.0 - imageWidth, bottom: 0, right: 0)

Solution 21 - Ios

You may forget about UIEdgeInsets and simply override frames in layoutSubviews() within your UIButton subclass.

To center the titleLable, simply add horizontal offset to the titleLabel frame by the difference between super.bounds.midX and titleLabel.frame.midX

   override func layoutSubviews() {
       super.layoutSubviews()
       
       if let label = titleLabel {
           label.frame = label.frame.offsetBy(dx: super.bounds.midX - 
                label.frame.midX , dy: 0)
       }

       // Available space to the left of the titleLabel is simply:
       let leftAvailableWidth = label.frame.minX

       imageView?.frame = CGRect(x: 0, y: 0, width: <Some width smaller than leftAvailableWidth>, height: super.bound.height)
   }

Solution 22 - Ios

@trishcode answer worked for me. I am just using it with an extension of the UIButton.

Here is the code:

extension UIButton {
func centerImageLeft(padding: CGFloat = 30.0){
    let buttonWidth = self.frame.width
    let textWidth = self.titleLabel?.intrinsicContentSize.width ?? 0
    let imageViewWidth = self.imageView?.frame.size.width ?? 0
    let offsetToLeftButtonEdge = buttonWidth - textWidth - imageViewWidth
    let offset = offsetToLeftButtonEdge - padding
    self.imageEdgeInsets = UIEdgeInsets(top: 0.0, left: 0, bottom: 0.0, right: offset)
}
}

You can then call it like this in the viewDidAppear Method:

button.centerImageLeft()

Solution 23 - Ios

Swift 5: You can achieve this by using custom class of UIButton.

class CustomButton: UIButton {
    
    var imageV = UIImageView()
    var titleV = UILabel()
    
    override func awakeFromNib() {
        
        self.imageView?.isHidden = true
        self.titleLabel?.isHidden = true
        
        imageV.frame = CGRect(x: 0, y: 0, width: 40, height: self.bounds.height)
        imageV.contentMode = .scaleAspectFit
        
        titleV.frame = CGRect(x: 40, y: 0, width: self.bounds.width - 40, height: self.bounds.height)
        titleV.font = self.titleLabel?.font
        titleV.textAlignment = .center
        
        self.addSubview(imageV)
        self.addSubview(titleV)

        imageV.image = self.imageView?.image; titleV.text = self.titleLabel?.text
        
        imageV.translatesAutoresizingMaskIntoConstraints = false
        imageV.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
        imageV.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
        imageV.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 0).isActive = true
        imageV.trailingAnchor.constraint(equalTo: titleV.leadingAnchor, constant: 0).isActive = true
        imageV.widthAnchor.constraint(equalToConstant: 40).isActive = true
        
        titleV.translatesAutoresizingMaskIntoConstraints = false
        titleV.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
        titleV.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
        titleV.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 0).isActive = true
    }
}

And later you can set image and text like this.

button.imageV.image = myImage
button.titleV.text = myText

Result

enter image description here

Solution 24 - Ios

Swift version:

var button = UIButton()

newGameButton.setTitle("Новая игра", for: .normal)
newGameButton.setImage(UIImage(named: "energi"), for: .normal)
newGameButton.backgroundColor = .blue
newGameButton.imageEdgeInsets.left = -50

enter image description here

Solution 25 - Ios

This works for me with varying button text sizes.

The key for an accurate button text width is to get the intrinsicContentSize. Since I'm using auto layout for the button width, I had to run this code from viewDidAppear instead of viewDidLoad so the button would be drawn already and, therefore, the button frame size would be accurate.

private func calculateAccountButtonImageViewOffset(button: UIButton, padding: CGFloat = 30.0) -> CGFloat {
    let buttonWidth = button.frame.width
    let textWidth = button.titleLabel?.intrinsicContentSize.width ?? 0
    let imageViewWidth = button.imageView?.frame.size.width ?? 0
    let offsetToLeftButtonEdge = buttonWidth - textWidth - imageViewWidth
    return offsetToLeftButtonEdge - padding
}

Usage:

let imageViewOffset = calculateAccountButtonImageViewOffset(button: button)
button.imageEdgeInsets = UIEdgeInsets(top: 0.0, left: 0, bottom: 0.0, right: imageViewOffset)

The button title can be offset as desired with Title Insets on IB: enter image description here

Solution 26 - Ios

It might be best to create a custom UIButton subclass to address this issues in a better manner. Apple might be 'resetting' your settings.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser1007721View Question on Stackoverflow
Solution 1 - Iosredent84View Answer on Stackoverflow
Solution 2 - IostoytoyView Answer on Stackoverflow
Solution 3 - IosAnBiswView Answer on Stackoverflow
Solution 4 - IosAlexView Answer on Stackoverflow
Solution 5 - IosDenis KozhukhovView Answer on Stackoverflow
Solution 6 - IosDeepak Kumar SahuView Answer on Stackoverflow
Solution 7 - IosMaximelcView Answer on Stackoverflow
Solution 8 - IosDaniloView Answer on Stackoverflow
Solution 9 - IosMatthew MitchellView Answer on Stackoverflow
Solution 10 - IosRémyView Answer on Stackoverflow
Solution 11 - IosbuildsucceededView Answer on Stackoverflow
Solution 12 - IosTushar KoulView Answer on Stackoverflow
Solution 13 - IosLucas van DongenView Answer on Stackoverflow
Solution 14 - IosEricView Answer on Stackoverflow
Solution 15 - IosManish ManandharView Answer on Stackoverflow
Solution 16 - IossandpatView Answer on Stackoverflow
Solution 17 - Iosnovecento88View Answer on Stackoverflow
Solution 18 - IosKupendiran iOSView Answer on Stackoverflow
Solution 19 - IosSergey SahakyanView Answer on Stackoverflow
Solution 20 - IosvbrittesView Answer on Stackoverflow
Solution 21 - IosTingView Answer on Stackoverflow
Solution 22 - IosOLLMPHView Answer on Stackoverflow
Solution 23 - IosZAFAR007View Answer on Stackoverflow
Solution 24 - Iosaturan23View Answer on Stackoverflow
Solution 25 - IostrishcodeView Answer on Stackoverflow
Solution 26 - IosChristianView Answer on Stackoverflow