81

I created a UIButton instance named "button" with an image using [UIButton setImage:forState:]. The button.frame is larger than the image's size.

Now I want to scale this button's image smaller. I tried changing button.imageView.frame, button.imageView.bounds and button.imageView.contentMode, but all seem ineffective.

Can anyone help me scale a UIButton's imageView?

I created the UIButton like this:

UIButton *button = [[UIButton alloc] init];
[button setImage:image forState:UIControlStateNormal];

I tried to scale the image like this:

button.imageView.contentMode = UIViewContentModeScaleAspectFit;
button.imageView.bounds = CGRectMake(0, 0, 70, 70);

and this:

button.imageView.contentMode = UIViewContentModeScaleAspectFit;
button.imageView.frame = CGRectMake(0, 0, 70, 70);
Pang
  • 9,564
  • 146
  • 81
  • 122
vcLwei
  • 1,927
  • 3
  • 16
  • 13

21 Answers21

94

For the original poster, here is the solution I found:

commentButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;

This will allow your button to scale horizontally. There is a vertical setting as well.

Took me several hours to figure that one out (the naming of the property is very unintuitive) so figured I'd share.

Chris
  • 3,577
  • 1
  • 21
  • 15
  • good sugggestion! my problem was on scaling stretched image to change size of leftbaritem button depends of its title. – Valerii Pavlov Nov 30 '11 at 10:21
  • 1
    This works but will not draw outside the bounds, think of it like aligning text in a line that you won't have anything pass the margins. So, you won't get the effect like UIViewContentModeScaleAspectFill (with some part of the image cropped) from this one. – Hlung Apr 02 '12 at 17:48
68

I'd faced similar problem, where I've a background Image (one with border) and an image (flag) for a custom button. I wanted flag to be scaled down and in center. I tried changing imageView's attribute but didn't succeed and was seeing this image --

enter image description here

During my experiments, I tried :

button.imageEdgeInsets = UIEdgeInsetsMake(kTop,kLeft,kBottom,kRight)

I achieved expected result as :

enter image description here

Hitesh Savaliya
  • 1,336
  • 13
  • 15
48

An Addition Way for config in XIB file. You can choose this option if you want text or image is Scale full fill in UIButton. It's will be the same with code.

UIButton *btn = [UIButton new];

btn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
btn.contentVerticalAlignment   = UIControlContentVerticalAlignmentFill;

enter image description here

Linh Nguyen
  • 2,006
  • 1
  • 20
  • 16
  • If you want to stretch image for UIButton is perfectly then You can use more support of image asset and Slicing this image. https://developer.apple.com/library/ios/recipes/xcode_help-image_catalog-1.0/chapters/SlicinganImage.html – Linh Nguyen Dec 16 '15 at 07:18
  • Wasn't even aware of this method. Rock on – Michael McKenna Jul 28 '17 at 19:58
25

use

button.contentMode = UIViewContentModeScaleToFill;

not

button.imageView.contentMode = UIViewContentModeScaleAspectFit;

Update:

As @Chris commented,

To get this to work for setImage:forState:, you need to do the following to scale horizontally: myButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;

Hemang
  • 26,840
  • 19
  • 119
  • 186
pavelpanov
  • 275
  • 3
  • 2
  • 3
    This works great in combination with [button setBackgroundImage:forState:]. Thanks. – Jason DeFontes Apr 16 '10 at 21:20
  • Note exactly what Jason said and you'll be good. It _doesn't_ work for setImage:forState: – dpjanes Aug 01 '11 at 12:31
  • 7
    To get this to work for setImage:forState:, you need to do the following to scale horizontally: myButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill; – Chris Nov 18 '11 at 08:53
15
    UIButton *button= [[UIButton alloc] initWithFrame:CGRectMake(0,0,70,70)];
    button.buttonType = UIButtonTypeCustom;
    UIImage *buttonImage = [UIImage imageNamed:@"image.png"];

    UIImage *stretchableButtonImage = [buttonImage stretchableImageWithLeftCapWidth:12 topCapHeight:0]; 
    [button setBackgroundImage:stretchableButtonImage forState:UIControlStateNormal]; 
EEE
  • 4,536
  • 3
  • 28
  • 34
  • @EEE Thank you.But there are 2 problem: 1. My question is use the UIButton's _imageView variable, not the _backgroundView variable. Have I to do it with backgroundView? 2. the function [UIImage stretchableImageWithLeftCapWidth:topCapHeight:] can only to make image larger, but can't make image smaller. Thanks all the same, and your answer solves my another question:I want to draw a title on the button with the image behind. I think the _backgroundImage can help me. Does this question has other better answer? – vcLwei Dec 24 '09 at 09:10
  • I see what you are trying to do and this is the way. if your image is bigger, then resize it using a tool, and everything you want to do will be done. Don't waste your time with_imageview. By the way if you like this asnwer, you can vote it up, and accept it – EEE Dec 24 '09 at 10:16
  • You can resize your image in Preview program in MacOS. Just open the image and selet tools-->Adjustsize – EEE Dec 24 '09 at 10:18
  • @EEE Yes,I can resize my image use a tool. But in my application sometimes I need the bigger image too, I don't want to two similar images only difference at size, that too waste space. And another way to do solve my question is that I can use CGBitmapContext to get a smaller image, but I guess this way is inconvenience compara to using _imageview. The reason I did not vote it up is my reputation is less than 15, actually I really want to do that. Thanks! – vcLwei Dec 24 '09 at 14:23
10

I found this solution.

1) Subclass the following methods of UIButton

+ (id)buttonWithType:(UIButtonType)buttonType {
    MyButton *toReturn = [super buttonWithType:buttonType];
    toReturn.imageView.contentMode = UIViewContentModeScaleAspectFit;
    return toReturn;
}

- (CGRect)imageRectForContentRect:(CGRect)contentRect {
    return contentRect;
}

And it works well.

Hemang
  • 26,840
  • 19
  • 119
  • 186
marcio
  • 2,729
  • 2
  • 25
  • 23
9

Strange, the only combo that worked for me (iOS 5.1) is...

button.imageView.contentMode = UIViewContentModeScaleAspectFit;

and

[button setImage:newImage forState:UIControlStateNormal];

Hlung
  • 13,850
  • 6
  • 71
  • 90
  • Originally I used: button.contentMode = UIViewContentModeScaleAspectFit; now I also need to write button.imageView.contentMode = UIViewContentModeScaleAspectFit; to keep aspect ratio on iPad 3 retina – Enrico Detoma Jul 13 '12 at 17:39
8

Just do (From Design OR From Code):

From Design

  1. Open your xib OR Storyboard.
  2. Select button
  3. Inside Attribute Inspector (Right side) > In "Control" section > select last 4th option for both Horizontal and Verical.

[For Point#3: Change Horizontal and vertical Align to UIControlContentHorizontalAlignmentFill and UIControlContentVericalAlignmentFill]

From Code

button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
button.contentVerticalAlignment =  UIControlContentVerticalAlignmentFill;
codercat
  • 22,873
  • 9
  • 61
  • 85
Sandip Patel - SM
  • 3,346
  • 29
  • 27
8

I just ran into this same problem, and there's a possible answer in this question:

Why does a custom UIButton image does not resize in Interface Builder?

Essentially, use the backgroundimage property instead, which does get scaled.

Community
  • 1
  • 1
JosephH
  • 37,173
  • 19
  • 130
  • 154
5

From small test I just did after reading here, depends if you use setImage or setBackgroundImage, both did the same result and strech the image

//for setBackgroundImage
 self.imageButton.contentMode = UIViewContentModeScaleAspectFill;
        [self.imageButton setBackgroundImage:[UIImage imageNamed:@"imgFileName"] forState:UIControlStateNormal];

//for setImage
 self.imageButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
        self.imageButton.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;
    [self.imageButton setImage:[UIImage imageNamed:@"imgFileName"] forState:UIControlStateNormal];
Hemang
  • 26,840
  • 19
  • 119
  • 186
user1105951
  • 2,259
  • 2
  • 34
  • 55
5

like this can solve your problem:

+ (UIImage*)resizedImage:(UIImage*)image
{
 CGRect frame = CGRectMake(0, 0, 60, 60);
 UIGraphicsBeginImageContext(frame.size);
 [image drawInRect:frame];
 UIImage* resizedImage = UIGraphicsGetImageFromCurrentImageContext();
 UIGraphicsEndImageContext();

 return resizedImage;
}
diatrevolo
  • 2,782
  • 26
  • 45
huangkui
  • 61
  • 1
  • 1
5

Storyboard

You must define specific property in Runtime Attributes of Identity inspectorimageView.contentModel, where you set value relatively to rawValue position of enum UIViewContentMode. 1 means scaleAspectFit.

Set button.imageView.contentMode in Storyboard

And button's alignment, in Attributes inspector:

Full alignment of button

Community
  • 1
  • 1
dimpiax
  • 12,093
  • 5
  • 62
  • 45
4
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
button.contentVerticalAlignment =  UIControlContentVerticalAlignmentFill;
Hemang
  • 26,840
  • 19
  • 119
  • 186
iomar
  • 465
  • 4
  • 4
2

This will also work, as the backgroundImage automatically scales

[button setBackgroundImage:image forState:UIControlStateNormal];

Elijah
  • 8,381
  • 2
  • 55
  • 49
2

I hope this can help to somebody else:

Swift 3+

button.contentHorizontalAlignment = UIControlContentHorizontalAlignment.fill
button.contentVerticalAlignment =  UIControlContentVerticalAlignment.fill
Dasoga
  • 5,489
  • 4
  • 33
  • 40
2

from @JosephH

contentHorizontalAlignment = UIControl.ContentHorizontalAlignment.fill contentVerticalAlignment = UIControl.ContentVerticalAlignment.fill

1

I can't get a solution use by _imageView, but I can use a CGContextRef to solve it. It use the UIGraphicsGetCurrentContext to get the currentContextRef and draw a image in currentContextRef, and then scale or rotate the image and create a new image. But it's not perfect.

the code:

-(UIImage*) scaleAndRotateImage:(UIImage*)photoimage width:(CGFloat)bounds_width height:(CGFloat)bounds_height;
{
    CGImageRef imgRef = photoimage.CGImage;

    CGFloat width = CGImageGetWidth(imgRef);
    CGFloat height = CGImageGetHeight(imgRef);

    CGAffineTransform transform = CGAffineTransformIdentity;
    CGRect bounds = CGRectMake(0, 0, width, height);

    bounds.size.width = bounds_width;
    bounds.size.height = bounds_height;

    CGFloat scaleRatio = bounds.size.width / width;
    CGFloat scaleRatioheight = bounds.size.height / height;
    CGSize imageSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef));
    CGFloat boundHeight;
    UIImageOrientation orient = photoimage.imageOrientation;
    switch(orient)
    {
        case UIImageOrientationUp: //EXIF = 1
            transform = CGAffineTransformIdentity;
            break;

        case UIImageOrientationUpMirrored: //EXIF = 2
            transform = CGAffineTransformMakeTranslation(imageSize.width, 0.0);
            transform = CGAffineTransformScale(transform, -1.0, 1.0);
            break;

        case UIImageOrientationDown: //EXIF = 3
            transform = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height);
            transform = CGAffineTransformRotate(transform, M_PI);
            break;

        case UIImageOrientationDownMirrored: //EXIF = 4
            transform = CGAffineTransformMakeTranslation(0.0, imageSize.height);
            transform = CGAffineTransformScale(transform, 1.0, -1.0);
            break;

        case UIImageOrientationLeftMirrored: //EXIF = 5
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeTranslation(imageSize.height, imageSize.width);
            transform = CGAffineTransformScale(transform, -1.0, 1.0);
            transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
            break;

        case UIImageOrientationLeft: //EXIF = 6
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeTranslation(0.0, imageSize.width);
            transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
            break;

        case UIImageOrientationRightMirrored: //EXIF = 7
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeScale(-1.0, 1.0);
            transform = CGAffineTransformRotate(transform, M_PI / 2.0);
            break;

        case UIImageOrientationRight: //EXIF = 8
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeTranslation(imageSize.height, 0.0);
            transform = CGAffineTransformRotate(transform, M_PI / 2.0);
            break;

        default:
            [NSException raise:NSInternalInconsistencyException format:@"Invalid?image?orientation"];
            break;
    }

    UIGraphicsBeginImageContext(bounds.size);

    CGContextRef context = UIGraphicsGetCurrentContext();

    if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft)
    {
        CGContextScaleCTM(context, -scaleRatio, scaleRatioheight);
        CGContextTranslateCTM(context, -height, 0);
    }
    else
    {
        CGContextScaleCTM(context, scaleRatio, -scaleRatioheight);
        CGContextTranslateCTM(context, 0, -height);
    }

    CGContextConcatCTM(context, transform);

    CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef);
    UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return imageCopy;
}
Hemang
  • 26,840
  • 19
  • 119
  • 186
vcLwei
  • 1,927
  • 3
  • 16
  • 13
0

Screenshot in XCode 8

At the bottom left of screenshot, you can see Stretching properties. Try using those.

haxgad
  • 387
  • 4
  • 9
0

You can modify imageView by using custom class of UIButton. Please see my answer. https://stackoverflow.com/a/59874762/5693826

ZAFAR007
  • 3,049
  • 1
  • 34
  • 45
0

Piggy backing off of another answer from 2020, I couldn't get the image to resize with the button. But this solved it :) Go ahead and set these properties in the init() (or wherever) for your button.

self.contentHorizontalAlignment = .fill
self.contentVerticalAlignment = .fill

Top button has those properties as .fill, bottom has default of .center

swappfunc
  • 1
  • 1
-1

Every UIButton has one hidden UIImageView of its own. So we have to set the content mode like the way given below...

[[btn imageView] setContentMode: UIViewContentModeScaleAspectFit];
[btn setImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal];
emraz
  • 1,563
  • 20
  • 28