scale Image in an UIButton to AspectFit?
Solution 1
If you really want to scale an image, do it, but you should resize it before using it. Resizing it at run time will just lose CPU cycles.
This is the category I'm using to scale an image :
UIImage+Extra.h
@interface UIImage (Extras)
- (UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize;
@end;
UIImage+Extra.m
@implementation UIImage (Extras)
- (UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize {
UIImage *sourceImage = self;
UIImage *newImage = nil;
CGSize imageSize = sourceImage.size;
CGFloat width = imageSize.width;
CGFloat height = imageSize.height;
CGFloat targetWidth = targetSize.width;
CGFloat targetHeight = targetSize.height;
CGFloat scaleFactor = 0.0;
CGFloat scaledWidth = targetWidth;
CGFloat scaledHeight = targetHeight;
CGPoint thumbnailPoint = CGPointMake(0.0,0.0);
if (!CGSizeEqualToSize(imageSize, targetSize)) {
CGFloat widthFactor = targetWidth / width;
CGFloat heightFactor = targetHeight / height;
if (widthFactor < heightFactor)
scaleFactor = widthFactor;
else
scaleFactor = heightFactor;
scaledWidth = width * scaleFactor;
scaledHeight = height * scaleFactor;
// center the image
if (widthFactor < heightFactor) {
thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
} else if (widthFactor > heightFactor) {
thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
}
}
// this is actually the interesting part:
UIGraphicsBeginImageContextWithOptions(targetSize, NO, 0);
CGRect thumbnailRect = CGRectZero;
thumbnailRect.origin = thumbnailPoint;
thumbnailRect.size.width = scaledWidth;
thumbnailRect.size.height = scaledHeight;
[sourceImage drawInRect:thumbnailRect];
newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
if(newImage == nil) NSLog(@"could not scale image");
return newImage ;
}
@end
You can use it to the size you want. Like :
[self.itemImageButton setImage:[stretchImage imageByScalingProportionallyToSize:CGSizeMake(20,20)]];
Solution 2
I had the same problem. Just set the ContentMode of the ImageView that is inside the UIButton.
[[self.itemImageButton imageView] setContentMode: UIViewContentModeScaleAspectFit];
[self.itemImageButton setImage:[UIImage imageNamed:stretchImage] forState:UIControlStateNormal];
Hope this helps.
Solution 3
None of the answers here really worked for me, I solved the problem with the following code:
button.contentMode = UIViewContentModeScaleToFill;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
button.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;
You can do this in the Interface Builder as well.
Solution 4
The easiest way to programmatically set a UIButton imageView in aspect fit mode :
Swift
button.contentHorizontalAlignment = .fill
button.contentVerticalAlignment = .fill
button.imageView?.contentMode = .scaleAspectFit
Objective-C
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
button.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;
button.imageView.contentMode = UIViewContentModeScaleAspectFit;
Note: You can change .scaleAspectFit (UIViewContentModeScaleAspectFit) to .scaleAspectFill (UIViewContentModeScaleAspectFill) to set an aspect fill mode
Solution 5
I had problems with the image not resizing proportionately so the way I fixed it was using edge insets.
fooButton.contentEdgeInsets = UIEdgeInsetsMake(10, 15, 10, 15);
Related videos on Youtube
Comments
-
KONG over 3 years
I want to add an image to a UIButton, and also want to scale my image to fit with the UIButton (make image smaller). Please show me how to do it.
This is what I have tried, but it does't work:
- Adding image to button and using
setContentMode
:
[self.itemImageButton setImage:stretchImage forState:UIControlStateNormal]; [self.itemImageButton setContentMode:UIViewContentModeScaleAspectFit];
- Making a "stretch image":
UIImage *stretchImage = [updatedItem.thumbnail stretchableImageWithLeftCapWidth:0 topCapHeight:0];
-
Shaun Budhram almost 13 yearsI think this has been changed to be the default behavior in firmware 4.0 and up.
-
Matt over 9 yearsSee stackoverflow.com/a/28205566/481207 for the solution.
- Adding image to button and using
-
KONG over 14 yearsThanks for your answer, Gcamp. I did have an method for resizing by ratio. But I still try to find a way to tell UIButton do it for me. My image is load from Internet so I can't resize it at compile time. BTW, thank you very much for your response.
-
Alexandre Gomes about 13 yearsMake sure you're setting the imageView. I also failed to notice, for a bit, that I was still using the backgroundImageView and it wasn't working for that.
-
Ben Gotow over 12 yearsBecause the image is placed into a CALayer, rendered, and cached by Quartz, performance should not be any worse if you place it in there at full size. Either way, you're resizing ~1 time. gcamp's answer is much more important if you're constantly resizing the button or doing other things that would trigger Quartz to redraw the image layer.
-
Yuanfei Zhu about 12 yearsIt seems this method has some problems when the button state is 'highlighted'. The image will back to the fill mode. Any idea?
-
Mickey over 11 yearsIt is not working to me. However, I make it work by using [self.itemImageButton setbackgroundImage:[UIImage imageNamed:stretchImage] forState:UIControlStateNormal];
-
Christopher over 11 yearsThis worked for me. I set the content mode as above. However, you also need to set the same image of the highlighted state in order to avoid the image going back to "fill mode". For example, [imageButton setImage:image forState:UIControlStateHighlighted];
-
onmyway133 over 10 years@Dave from Apple doc about imageView The button’s image view. (read-only) that's why it does not work
-
manecosta almost 10 yearsYou're not setting a content mode, you're setting the image. And they're not events, they're states. You're making a big mess. This is totally unrelated to the question.
-
Andy about 9 yearsThis worked for me -- but only if I selected to use the "Background Image", not the actual image. Whatever works! This was driving me NUTS.
-
Khant Thu Linn about 9 yearsit seems like image quality is reduced. i am testing on iphone 6 plus. Is it true? I also have 3x image.
-
gcamp about 9 yearsYes it will, this code is pretty old. It was
UIGraphicsBeginImageContext
instead ofUIGraphicsBeginImageContextWithOptions
. Just fixed it. -
RoLYroLLs about 9 yearsUnder Xcode 6.2 this worked for me but like @AndrewHeinlein said, used
Background Image
-
bendytree about 9 yearsYou can do this in Interface Builder with key path
imageView.contentMode
, typeNumber
, and value1
-
sdsykes almost 9 yearsThat should be yourButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
-
Tulleb almost 9 yearsDidn't try with .imageView. It is working without pretty well.
-
SHS over 8 yearsapple help for how to do "bendytree" comment process in Interface Builder - developer.apple.com/library/mac/recipes/…
-
Radu Simionescu over 8 yearsyeah but in many cases it doesn't matter if you loose a few cycles, so no point in filling up the ram
-
Ortwin Gentz about 8 yearsThis doesn't give you aspect fit behavior as asked by the OP.
-
Daniel about 8 years@OrtwinGentz you can select the mode and set
Aspect fit
instead ofscale to fill
. -
Iulian Onofrei over 7 yearsIsn't this possible without a subclass?
-
Andy Poes over 7 yearsThis answer was specifically for backgroundImage. For the main image you can monkey with the the imageEdgeInsets.
-
Iulian Onofrei over 7 yearsI know, and I wanted if it's possible to achieve this without a subclass.
-
Andy Poes over 7 yearsAs far as I know, you cannot adjust the backgroundImage without subclassing.
-
BharathRao almost 5 yearsNice answer bro..helped me a lot. Thanks!