escalar imagen en un UIButton a AspectFit?

94

Quiero agregar una imagen a un UIButton, y también quiero escalar mi imagen para que encaje con el UIButton (hacer la imagen más pequeña). Por favor enséñame cómo hacerlo.

Esto es lo que he probado, pero no funciona:

  • Agregar imagen al botón y usar setContentMode:
[self.itemImageButton setImage:stretchImage forState:UIControlStateNormal];
[self.itemImageButton setContentMode:UIViewContentModeScaleAspectFit];
  • Hacer una "imagen estirada":
UIImage *stretchImage = [updatedItem.thumbnail stretchableImageWithLeftCapWidth:0 topCapHeight:0];
KONG
fuente
Creo que esto se ha cambiado para que sea el comportamiento predeterminado en el firmware 4.0 y posteriores.
Shaun Budhram
1
Consulte stackoverflow.com/a/28205566/481207 para conocer la solución.
Matt

Respuestas:

28

Si realmente desea escalar una imagen, hágalo, pero debe cambiar su tamaño antes de usarla. Cambiar su tamaño en tiempo de ejecución solo perderá ciclos de CPU.

Esta es la categoría que estoy usando para escalar una imagen:

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

Puedes usarlo al tamaño que quieras. Me gusta :

[self.itemImageButton setImage:[stretchImage imageByScalingProportionallyToSize:CGSizeMake(20,20)]];
gcamp
fuente
Gracias por tu respuesta, Gcamp. Tenía un método para cambiar el tamaño por proporción. Pero todavía trato de encontrar una manera de decirle a UIButton que lo haga por mí. Mi imagen se carga desde Internet, por lo que no puedo cambiar su tamaño en tiempo de compilación. Por cierto, muchas gracias por tu respuesta.
KONG
2
Debido a que la imagen se coloca en un CALayer, Quartz la procesa y la almacena en caché, el rendimiento no debería ser peor si la coloca allí a tamaño completo. De cualquier manera, está cambiando el tamaño ~ 1 vez. La respuesta de gcamp es mucho más importante si constantemente cambia el tamaño del botón o hace otras cosas que harían que Quartz redibujara la capa de la imagen.
Ben Gotow
parece que la calidad de la imagen se reduce. estoy probando en iphone 6 plus. ¿Es verdad? También tengo una imagen de 3x.
Khant Thu Linn
Sí, este código es bastante antiguo. Fue en UIGraphicsBeginImageContextlugar de UIGraphicsBeginImageContextWithOptions. Solo lo arreglé.
gcamp
sí, pero en muchos casos no importa si pierde algunos ciclos, por lo que no tiene sentido llenar la memoria RAM
Radu Simionescu
203

Yo tuve el mismo problema. Simplemente configure el ContentMode de ImageView que está dentro del UIButton.

[[self.itemImageButton imageView] setContentMode: UIViewContentModeScaleAspectFit];
[self.itemImageButton setImage:[UIImage imageNamed:stretchImage] forState:UIControlStateNormal];

Espero que esto ayude.

Dave
fuente
14
Asegúrate de configurar imageView . Tampoco me di cuenta, por un momento, de que todavía estaba usando backgroundImageView y no estaba funcionando para eso.
Alexandre Gomes
2
Parece que este método tiene algunos problemas cuando el estado del botón está "resaltado". La imagen volverá al modo de relleno. ¿Alguna idea?
Yuanfei Zhu
No me está funcionando. Sin embargo, lo hago funcionar usando [self.itemImageButton setbackgroundImage: [UIImage imageNamed: stretchImage] forState: UIControlStateNormal];
Mickey
3
Esto funcionó para mí. Configuré el modo de contenido como arriba. Sin embargo, también debe configurar la misma imagen del estado resaltado para evitar que la imagen vuelva al "modo de relleno". Por ejemplo, [imageButton setImage: image forState: UIControlStateHighlights];
Christopher
1
Puede hacer esto en Interface Builder con la ruta clave imageView.contentMode, el tipo Numbery el valor1
bendytree
107

Ninguna de las respuestas aquí realmente funcionó para mí, resolví el problema con el siguiente código:

button.contentMode = UIViewContentModeScaleToFill;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
button.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;

También puede hacer esto en Interface Builder.

ingrese la descripción de la imagen aquí

nalexn
fuente
5
Esto no le da un comportamiento de ajuste de aspecto como lo pide el OP.
Ortwin Gentz
3
@OrtwinGentz ​​puede seleccionar el modo y configurar en Aspect fitlugar de scale to fill.
Daniel
55

La forma más sencilla de configurar mediante programación un UIButton imageView en modo de ajuste de aspecto :

Rápido

button.contentHorizontalAlignment = .fill
button.contentVerticalAlignment = .fill
button.imageView?.contentMode = .scaleAspectFit

C objetivo

button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
button.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;
button.imageView.contentMode = UIViewContentModeScaleAspectFit;

Nota: Puede cambiar .scaleAspectFit (UIViewContentModeScaleAspectFit) a .scaleAspectFill (UIViewContentModeScaleAspectFill) para establecer un modo de relleno de aspecto

Tanguy G.
fuente
20

Tuve problemas con la imagen que no cambiaba de tamaño proporcionalmente, por lo que la forma en que la arreglé fue con inserciones de borde.

fooButton.contentEdgeInsets = UIEdgeInsetsMake(10, 15, 10, 15);
ninjaneer
fuente
16

Esto ahora se puede hacer a través de las propiedades UIButton de IB. La clave es configurar su imagen como fondo, de lo contrario no funcionará.

ingrese la descripción de la imagen aquí

capikaw
fuente
14

Ampliando la respuesta de Dave, puede configurar todos contentModelos botones imageViewen IB, sin ningún código, usando Atributos de tiempo de ejecución:

ingrese la descripción de la imagen aquí

  • 1 medio UIViewContentModeScaleAspectFit ,
  • 2significaría UIViewContentModeScaleAspectFill.
Ortwin Gentz
fuente
8

Si simplemente desea reducir la imagen de su botón:

yourButton.contentMode = UIViewContentModeScaleAspectFit;
yourButton.imageEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10);
Tulleb
fuente
Ese debería ser yourButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
sdsykes
No probé con .imageView. Está funcionando sin bastante bien.
Tulleb
5

1 - Borrar texto predeterminado del botón (importante)

2 - establecer alineación como imagen

3 - establece el modo de contenido como imagen

ingrese la descripción de la imagen aquí

Hamid Reza Ansari
fuente
Buena respuesta hermano ... me ayudó mucho. ¡Gracias!
BharathRao
5

Tengo un método que lo hace por mí. El método toma UIButtony ajusta el aspecto de la imagen.

-(void)makeImageAspectFitForButton:(UIButton*)button{
    button.imageView.contentMode=UIViewContentModeScaleAspectFit;
    button.contentHorizontalAlignment=UIControlContentHorizontalAlignmentFill;
    button.contentVerticalAlignment=UIControlContentVerticalAlignmentFill;
}
Abedalkareem Omreyh
fuente
4

La solución más limpia es utilizar Auto Layout . Bajé contenido Prioridad Resistencia a la Compresión de mi UIButtony establecer la imagen (no la imagen de fondo ) a través de Interface Builder . Después de eso, agregué un par de restricciones que definen el tamaño de mi botón (bastante complejo en mi caso) y funcionó de maravilla.

Rudolf Adamkovič
fuente
Esto funcionó para mí, pero solo si seleccioné usar la "Imagen de fondo", no la imagen real. ¡Lo que sea que funcione! Esto me estaba volviendo loco.
Andy
En Xcode 6.2 esto funcionó para mí, pero como dijo @AndrewHeinlein, usadoBackground Image
RoLYroLLs
3

asegúrese de haber configurado la imagen en la propiedad Imagen, pero no en el Fondo

Andrés
fuente
2

La imagen de fondo se puede configurar para escalar el relleno de aspecto con bastante facilidad. Solo necesito hacer algo como esto en una subclase de UIButton:

- (CGRect)backgroundRectForBounds:(CGRect)bounds
{
    // you'll need the original size of the image, you 
    // can save it from setBackgroundImage:forControlState
    return CGRectFitToFillRect(__original_image_frame_size__, bounds);
}

// Utility function, can be saved elsewhere
CGRect CGRectFitToFillRect( CGRect inRect, CGRect maxRect )
{
    CGFloat origRes = inRect.size.width / inRect.size.height;
    CGFloat newRes = maxRect.size.width / maxRect.size.height;

    CGRect retRect = maxRect;

    if (newRes < origRes)
    {
        retRect.size.width = inRect.size.width * maxRect.size.height / inRect.size.height;
        retRect.origin.x = roundf((maxRect.size.width - retRect.size.width) / 2);
    }
    else
    {
        retRect.size.height = inRect.size.height * maxRect.size.width / inRect.size.width;
        retRect.origin.y = roundf((maxRect.size.height - retRect.size.height) / 2);
    }

    return retRect;
}
Andy Poes
fuente
¿No es esto posible sin una subclase?
Iulian Onofrei
Esta respuesta fue específicamente para backgroundImage. Para la imagen principal puedes usar el imageEdgeInsets.
Andy Poes
Lo sé, y quería si es posible lograr esto sin una subclase.
Iulian Onofrei
Hasta donde yo sé, no se puede ajustar backgroundImage sin subclases.
Andy Poes
1

Swift 5.0

 myButton2.contentMode = .scaleAspectFit
 myButton2.contentHorizontalAlignment = .fill
 myButton2.contentVerticalAlignment = .fill
Qasim Mirza
fuente
0

Para Xamarin.iOS (C #):

    myButton.VerticalAlignment = UIControlContentVerticalAlignment.Fill;
    myButton.HorizontalAlignment = UIControlContentHorizontalAlignment.Fill;
    myButton.ImageView.ContentMode = UIViewContentMode.ScaleAspectFit;
Maciej
fuente
-1

Solo necesita configurar el modo de contenido de UIButton imageview para tres eventos. -

[cell.button setImage:[UIImage imageWithData:data] forState:UIControlStateNormal];

[cell.button setImage:[UIImage imageWithData:data] forState:UIControlStateHighlighted];

[cell.imgIcon setImage:[UIImage imageWithData:data] forState:UIControlStateSelected];

Tenemos un código para tres eventos bcoz mientras resaltamos o seleccionamos si el tamaño del botón es CUADRADO y el tamaño de la imagen es rectangular, entonces se mostrará una imagen cuadrada en el momento de resaltar o seleccionar.

Estoy seguro de que le funcionará.

ruyamonis346
fuente
No está configurando un modo de contenido, está configurando la imagen. Y no son eventos, son estados. Estás haciendo un gran lío. Esto no tiene nada que ver con la pregunta.
manecosta