204

How can I adjust the image size of the UIButton? I am setting the image like this:

[myLikesButton setImage:[UIImage imageNamed:@"icon-heart.png"] forState:UIControlStateNormal];

However this fills up the image to the full button, how do I make the image smaller?


Historic note:

For this now 10+ yr old question, you now typically just set the point size using setPreferredSymbolConfiguration

Fattie
  • 27,874
  • 70
  • 431
  • 719
adit
  • 32,574
  • 72
  • 229
  • 373
  • 1
    @CodaFi is right, you should generally provide assets at the right size as it reduces any work for the CPU, uses less memory and will most likely look better as you do not potentially introduce any scaling artefacts... – Paul.s May 14 '12 at 01:53
  • Also you can make the button to the size of image (or vice-versa).Why have have a big button ...with a small image in it.Simply add the image you want , that's what custom buttons are for or you can explain the logic you want to implement for others to have a clear idea. – Abhishek Singh May 14 '12 at 02:27

19 Answers19

276

If I understand correctly what you're trying to do, you need to play with the buttons image edge inset. Something like:

myLikesButton.imageEdgeInsets = UIEdgeInsets(top: 30, left: 30, bottom: 30, right: 30)
liudasbar
  • 173
  • 4
  • 11
Tim C
  • 2,920
  • 1
  • 15
  • 4
120

Tim's answer is correct, however I wanted to add another suggestion, because in my case there was a simpler solution altogether.

I was looking to set the UIButton image insets because I didn't realize that I could set the content mode on the button's UIImageView, which would have prevented the need to use UIEdgeInsets and hard-coded values altogether. Simply access the underlying imageview on the button and set the content mode:

myButton.imageView.contentMode = UIViewContentModeScaleAspectFit;

See UIButton doesn't listen to content mode setting?

Swift 3

myButton.imageView?.contentMode = .scaleAspectFit
Community
  • 1
  • 1
Kyle Clegg
  • 38,547
  • 26
  • 130
  • 141
97

Swift :

button.setImage(UIImage(named: "checkmark_white"), for: .normal)
button.contentVerticalAlignment = .fill
button.contentHorizontalAlignment = .fill
button.imageEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
stackich
  • 3,607
  • 3
  • 17
  • 41
Josh O'Connor
  • 4,694
  • 7
  • 54
  • 98
  • 11
    This worked beautifully for me. I created a PDF icon within Inkscape and the `contentVerticalAlignment/contentHorizontalAlignment` options got enabled me to scale it the way I was hoping to. Thank you for posting this. – Adrian May 08 '18 at 15:36
  • 5
    setting `contentHorizontalAlignment` and `contentVerticalAlignment` did the trick – Tom Knapen Nov 14 '18 at 13:20
  • 2
    This solution works great when using PDF assets for icons. Thank you! – Eneko Alonso Jun 16 '20 at 20:42
  • contentVerticalAlignment and contentHorizontalAlignment did work to me, whose UIImageView was too small in UIButton. – KoreanXcodeWorker Jan 05 '21 at 14:27
  • ...thus also working perfectly fine for System Icons / SF Symbols – thanks! – emmics Feb 02 '21 at 07:12
63

Here is the other solution to scale an imageView of UIButton.

button.imageView?.layer.transform = CATransform3DMakeScale(0.8, 0.8, 0.8)
ovo
  • 1,904
  • 13
  • 26
48

You can also do that from inteface builder like this.

enter image description here

I think it's helpful.

Milos Mandic
  • 1,046
  • 2
  • 13
  • 19
45

If your image is too large (and you can't/don't want to just made the image smaller), a combination of the first two answers works great.

addButton.imageView?.contentMode = .scaleAspectFit
addButton.imageEdgeInsets = UIEdgeInsetsMake(15.0, 15.0, 15.0, 5.0)

Unless you get the image insets just right, the image will be skewed without changing the contentMode.

Forge
  • 6,538
  • 6
  • 44
  • 64
iosjillian
  • 2,118
  • 1
  • 14
  • 8
24

you can use imageEdgeInsets property The inset or outset margins for the rectangle around the button’s image.

 [self.btn setImageEdgeInsets:UIEdgeInsetsMake(6, 6, 6, 6)];

A positive value shrinks, or insets, that edge—moving. A negative value expands, or outsets, that edge.

safaa elgendi
  • 239
  • 3
  • 3
16

Heres the Swift version:

myButton.imageEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
Esqarrouth
  • 38,543
  • 21
  • 161
  • 168
11

If you are using symbolic images for the button, then this solution is better:

button.setPreferredSymbolConfiguration(UIImage.SymbolConfiguration(pointSize: 48), forImageIn: .normal)
Alexander Volkov
  • 7,904
  • 1
  • 47
  • 44
11

Insetting the image works for me, but I also needed the button Type to be Custom and the button Style to be Default. The defaults for a button added in Xcode 13 are System for Type and Plain for Style.

self.imageEdgeInsets = UIEdgeInsets(top: 3.0, left: 3.0, bottom: 3.0, right: 3.0)

enter image description here

trishcode
  • 3,299
  • 1
  • 18
  • 25
9

Swift 4

You would need to use these two lines of code, in this specific order. All you need is to change the top and bottom value of the edge insets.

addButton.imageView?.contentMode = .scaleAspectFit
addButton.imageEdgeInsets = UIEdgeInsetsMake(10.0, 0.0, 10.0, 0.0)
Van Du Tran
  • 6,736
  • 11
  • 45
  • 55
7

With the help of Tim C's answer, I was able to create an extension on UIButton using Swift that allows you to specify the image frame by using the .setImage() function with an extra frame parameter

extension UIButton{

    func setImage(image: UIImage?, inFrame frame: CGRect?, forState state: UIControlState){
        self.setImage(image, forState: state)

        if let frame = frame{
            self.imageEdgeInsets = UIEdgeInsets(
                top: frame.minY - self.frame.minY,
                left: frame.minX - self.frame.minX,
                bottom: self.frame.maxY - frame.maxY,
                right: self.frame.maxX - frame.maxX
            )
        }
    }

}

Using this, if you wanted to set the frame of a UIButton to CGRectMake(0, 0, 64, 64), and set the image of it to myImage with a frame of CGRectMake(8, 8, 48, 48), you could use

let button: UIButton = UIButton(frame: CGRectMake(0, 0, 64, 64))
button.setImage(
    myImage,
    inFrame: CGRectMake(8, 8, 48, 48),
    forState: UIControlState.Normal
)
Community
  • 1
  • 1
Jojodmo
  • 23,357
  • 13
  • 65
  • 107
  • 6
    You should `if let` instead of checking if `frame` is `nil` and then [force unwrapping a zillion times](https://i.imgflip.com/utfq7.jpg). – fpg1503 Apr 07 '16 at 19:49
7

When changing icon size with UIEdgeInsetsMake(top, left, bottom, right), keep in mind button dimensions and the ability of UIEdgeInsetsMake to work with negative values as if they are positive.

Example: Two buttons with height 100 and aspect 1:1.

left.imageEdgeInsets = UIEdgeInsetsMake(40, 0, 40, 0)
right.imageEdgeInsets = UIEdgeInsetsMake(40, 0, 40, 0)

enter image description here

left.imageEdgeInsets = UIEdgeInsetsMake(40, 0, 40, 0)
right.imageEdgeInsets = UIEdgeInsetsMake(45, 0, 45, 0)

enter image description here

left.imageEdgeInsets = UIEdgeInsetsMake(40, 0, 40, 0)
right.imageEdgeInsets = UIEdgeInsetsMake(60, 0, 60, 0)

enter image description here

Examples 1 and 3 are identical since ABS(100 - (40 + 40)) = ABS(100 - (60 + 60))

Borys T
  • 239
  • 2
  • 13
5

Updated for Swift > 5

set the size:

button.frame = CGRect(x: 0, y: 0, width: 44, height: 44)

set margins:

button.imageEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
skantus
  • 943
  • 10
  • 21
4

One approach is to resize the UIImage in code like the following. Note: this code only scales by height, but you can easily adjust the function to scale by width as well.

let targetHeight = CGFloat(28)
let newImage = resizeImage(image: UIImage(named: "Image.png")!, targetHeight: targetHeight)
button.setImage(newImage, for: .normal)

fileprivate func resizeImage(image: UIImage, targetHeight: CGFloat) -> UIImage {
    // Get current image size
    let size = image.size

    // Compute scaled, new size
    let heightRatio = targetHeight / size.height
    let newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio)
    let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)

    // Create new image
    UIGraphicsBeginImageContextWithOptions(newSize, false, 0)
    image.draw(in: rect)
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    // Return new image
    return newImage!
}
Crashalot
  • 33,605
  • 61
  • 269
  • 439
2

Swift 3

I set myButton width and height to 40 and my padding from EdgeInsetsMake is 15 all sides. I suggest to add a background color to your button to see the actual padding.

myButton.backgroundColor = UIColor.gray // sample color to check padding
myButton.imageView?.contentMode = .scaleAspectFit
myButton.imageEdgeInsets = UIEdgeInsetsMake(15, 15, 15, 15)
Drey
  • 59
  • 1
  • 9
1

Updated for Swift 3

yourButtonName.imageEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10)
iAj
  • 3,787
  • 1
  • 31
  • 34
1

If you don't want to play around with image insets and you are using auto layout (which I assume you do), another solution is to add size constraints to the image view. Make sure the constraints have a priority of 999, otherwise auto layout will complain.

guard let imageView = button.imageView else { return }

let size = CGSize(width: 20, height: 20)
let sizeConstraints = [
    imageView.widthAnchor.constraint(equalToConstant: size.width),
    imageView.heightAnchor.constraint(equalToConstant: size.height)
]
imageView.translatesAutoresizingMaskIntoConstraints = false
sizeConstraints.forEach { $0.priority = UILayoutPriority(rawValue: priority) }
NSLayoutConstraint.activate(sizeConstraints)
imageView.contentMode = .scaleAspectFit
Balázs Vincze
  • 3,550
  • 5
  • 29
  • 60
-6

i think, your image size is also same as button size then you put image in background of the button like :

[myLikesButton setBackgroundImage:[UIImage imageNamed:@"icon-heart.png"] forState:UIControlStateNormal];

you mast have same size of image and button.i hope you understand my point.

Dev
  • 390
  • 2
  • 11