UIButton no irá a Aspect Fit en iPhone

105

Tengo un par de UIButtons, y en IB están configurados en Aspect Fit, pero por alguna razón siempre se estiran. ¿Hay algo más que tengas que configurar? Probé todos los modos de vista diferentes y ninguno de ellos funciona, todos se estiran.

marty
fuente
La respuesta de @Werner Altesischer es la correcta. Realice los cambios apropiados.
Harshit Gupta
1
@marty ¿Estás configurando una imagen de fondo o una imagen? La imagen de fondo no lo admite, solo la imagen.
Juan Boero

Respuestas:

45

Ya tuve ese problema antes. Lo resolví poniendo mi imagen en un lugar UIImageViewdonde la contentModeconfiguración realmente funciona, y colocando una personalizada transparente UIButtonencima de eso.

EDITAR: Esta respuesta es obsoleta. Consulte la respuesta de @Werner Altewischer para obtener la respuesta correcta en las versiones modernas de iOS.

Dan Ray
fuente
Sí, lo intenté, pero ahora no puedo hacer que el botón se reajuste a la imagen
marty
¿Cómo gestiona los estados de los botones con esta técnica? Parece que responder a la interacción del usuario como "resaltado" sería una pesadilla.
SooDesuNe
3
Esta podría haber sido la forma correcta de hacer esto hace 2.5 años cuando se respondió esta pregunta, pero ahora puede editar el ImageView interno de UIButton y establecer el modo de contenido allí. Vea la respuesta de @Werner Altewischer
Steve Haley
233

La solución es establecer contentModeen la imageViewpropiedad de UIButton. El UIButtontiene que ser creado con el tipo personalizado para que esto funcione creo (de lo contrario nilse devuelve para esta propiedad).

Werner Altewischer
fuente
67
Esto funcionó para mí:[button.imageView setContentMode:UIViewContentModeScaleAspectFit];
ayreguitar
2
Esto también funciona para mí, pero si configuro adjustsImageWhenHighlights = YES, la imagen se vuelve a estirar cuando toco el botón.
cduck
1
El estiramiento en adjustsImage ha sido eliminado en iOS 6.
Ben Flynn
3
En iOS 8, esto en realidad no me funciona. La respuesta original (con colocar un imageView detrás de un botón transparente) funciona mejor.
user1416564
3
en Swift du jour:button.imageView!.contentMode = UIViewContentMode.scaleAspectFit
Nestor
57

Este método me funcionó muy bien:

En Xib seleccione el botón y configure user defined runtime attributes:

  • Ruta clave: self.imageView.contentMode
  • Tipo: Number
  • Valor: 1

Haga clic aquí para ver más claramente la solución

Usamos number porque no puedes usar enum allí. Pero UIViewContentModeScaleAspectFit es igual a 1.

István Stefánovics
fuente
2
Esto también actualizó la imagen en el generador de interfaces durante el tiempo de diseño. Gran solucion
George Filippakos
Gran solución, poco código y funciona como un encanto, la enumeración se basa en elementos de la lista del modo de contenido.
Kross
También puede agregar una extensión para que sea un poco más fácil: extension UIButton { @IBInspectable var imageContentMode: Int { get {return imageView?.contentMode.rawValue ?? 0} set {imageView?.contentMode = UIViewContentMode(rawValue: newValue) ?? .scaleAspectFit} } }
Yonat
¡Sin 'yo' imageView.contentModefuncionó para mí!
porJeevan
22

Si está haciendo esto en Interface Builder, puede usar el inspector de atributos en tiempo de ejecución para configurarlo directamente sin ningún código.

Establezca la ruta de la clave en el botón para que sea "imageView.contentMode" con un tipo de "Número" y un valor de "1" (o el modo que desee).

imageview.contentMode = 1

Averydev
fuente
14

Utilice imageView del botón para contentMode. No directamente en el propio botón.

homeButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
homeButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
homeButton.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;
[homeButton setImage:[UIImage imageNamed:kPNGLogo] forState:UIControlStateNormal];
Ahmed Elashker
fuente
6

Si coloca la imagen UIImageViewdetrás del botón, perderá la funcionalidad incorporada de la UIButtonclase, como adjustsImageWhenHighlightedy adjustsImageWhenDisabled, y, por supuesto, la capacidad de configurar diferentes imágenes para diferentes estados (sin la molestia de hacerlo usted mismo).

Si queremos tener una imagen sin estirar para todos los estados de control , una cosa es obtener la imagen usando imageWithCGImage:scale:orientation, como en el siguiente método:

- (UIImage *) getScaledImage:(UIImage *)img insideButton:(UIButton *)btn {

    // Check which dimension (width or height) to pay respect to and
    // calculate the scale factor
    CGFloat imgRatio = img.size.width / img.size.height, 
            btnRatio = btn.frame.size.width / btn.frame.size.height,
            scaleFactor = (imgRatio > btnRatio 
                           ? img.size.width / btn.frame.size.width
                           : img.size.height / btn.frame.size.height;

    // Create image using scale factor
    UIImage *scaledImg = [UIImage imageWithCGImage:[img CGImage]
                                             scale:scaleFactor
                                       orientation:UIImageOrientationUp];
    return scaledImg;
}

Para implementar esto escribiríamos:

UIImage *scaledImg = [self getScaledImage:myBtnImg insideButton:myBtn];
[myBtn setImage:scaledImg forState:UIControlStateNormal];

Esto debería evitar que la imagen se estire en todos los estados de control. Me funcionó, ¡pero avíseme si no funciona!

NOTA: Aquí estamos abordando un problema relacionado con UIButton, pero insideButton:bien podría ser insideView:, o lo que sea que a uno le gustaría encajar la imagen.

Alexander Wallin
fuente
6

Tuve este problema hace un tiempo. El problema que tuve fue que estaba tratando de aplicar este efecto al UIButton de fondo, que es limitado y, por lo tanto, significa que no puede ajustarlo tan fácilmente.

El truco es configurarlo como solo una imagen y luego aplicar la técnica de @ayreguitar y eso debería solucionarlo.

UIButton *myButton = [UIButton buttonWithType:UIButtonTypeCustom];
[myButton setContentMode:UIViewContentModeScaleAspectFill];
[myButton setImage:@"myImage.png" forState:UIControlStateNormal];
Joe Barbour
fuente
4

Esto funcionó para mi

[button.imageView setContentMode:UIViewContentModeScaleAspectFit];

Gracias a @ayreguitar por su comentario

Karan Alangat
fuente
4

Aquí hay una respuesta alternativa en rápido:

myButton.imageView?.contentMode = .ScaleAspectFit
João Neves
fuente
4

Combinando algunas respuestas diferentes en una solución: cree un botón con un tipo personalizado, establezca la propiedad imageView contentMode del botón y establezca la imagen para el botón (no la imagen de fondo, que aún se escalará para llenar).

//Objective-C:
UIImage *image = [UIImage imageNamed:"myImageName.png"];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setImage:image forState:UIControlStateNormal];
button.imageView.contentMode = UIViewContentModeScaleAspectFit;

//Swift:
let image = UIImage(named: "myImageName.png")
let button = UIButton(type: .custom)
button.imageView?.contentMode = .scaleAspectFit
button.setImage(image, for: .normal)
Estafador
fuente
3
btn.imageView.contentMode = UIViewContentModeScaleAspectFit;
selaband
fuente
Si bien este fragmento de código puede resolver la pregunta, incluir una explicación realmente ayuda a mejorar la calidad de su publicación. Recuerde que está respondiendo a la pregunta para los lectores en el futuro, y es posible que esas personas no conozcan los motivos de su sugerencia de código. - De la revisión
Ferrybig
2

Esta respuesta se basa en la respuesta de @ WernerAltewischer .

Para evitar tener que conectar mi botón a un IBOutlet para ejecutar el código en él, subclasé la clase de UIButton:

// .h
@interface UIButtonWithImageAspectFit : UIButton
@end

// .m
@implementation UIButtonWithImageAspectFit

- (void) awakeFromNib {
    [self.imageView setContentMode:UIViewContentModeScaleAspectFit];
}

@end



Ahora cree un botón personalizado en su xib y configure su imagen (no la imagen de fondo):

UIButtonWithImageAspectFit: crear y establecer una imagen


Luego, establezca su clase:

UIButtonWithImageAspectFit: establecer clase personalizada

¡Listo!
En lugar del
UIButton sin ajuste de aspecto de imagen
ajuste de aspecto de la imagen de su botón, ahora es el esperado:
Botón UIB con ajuste de aspecto de imagen

Guillaume
fuente
2

ios 12. Debes agregar también la alineación de contenido

class FitButton: UIButton {

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)


    }

    override func layoutSubviews() {
        self.imageView?.contentMode = .scaleAspectFill
        self.contentHorizontalAlignment = .fill
        self.contentVerticalAlignment = .fill
        super.layoutSubviews()


    }

}
João Nunes
fuente
1

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
1

Los modos de contenido de UIView se aplican al "contenido" del CALayer correspondiente. Esto funciona para UIImageViews porque establecen el CALayercontenido en el correspondiente CGImage.

drawRect: finalmente se renderiza al contenido de la capa.

Un personalizado UIButton(hasta donde yo sé) no tiene contenido (los botones de estilo rectángulo redondeado pueden renderizarse usando contenido). El botón tiene subvistas: el fondo UIImageView, la imagen UIImageViewy el título UILabel. Configurar el contentModeen las subvistas puede hacer lo que quiera, pero jugar con la UIButtonjerarquía de vistas es un poco prohibido .

tc.
fuente
1

Cambiar UIButton.imageView.contentModeno funcionó para mí.
Resolví el problema configurando la imagen en la propiedad 'Fondo'.
Puede agregar una restricción de relación si lo necesita

Parque Soohwan
fuente
1

Esto se superpone a muchas de las otras respuestas, pero la solución para mí fue

  • establezca el contentModedel UIImageViewpara el botón en .ScaleAspectFit- lo que se puede hacer en los "Atributos de tiempo de ejecución definidos por el usuario" en Interface Builder (es decir self.imageView.contentMode, Número, 1) o en unUIButton subclase;
  • deshabilitar "Autoresize Subviews";
  • establezca "Borde" en "Imagen" y los valores "Superior" e "Inferior" apropiados para "Recuadro" (que puede que solo sea necesario si usted, como yo, utilizó un PDF como imagen).
Plindberg
fuente
0

Puede usar imageWithCGImage como se muestra arriba (pero sin los paréntesis que faltan).

Además ... millones de teléfonos que no sean 4.0 no funcionarán con ese código en absoluto.

Alicia
fuente
0

[button sizeToFit] trabajó para mi.

Hila
fuente
0

Similar a @Guillaume, he creado una subclase de UIButton como Swift-File. Luego configure mi clase personalizada en el Interface Builder:

constructor de interfaz.

Y aquí el archivo Swift:

import UIKit

class TRAspectButton : UIButton {
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.imageView?.contentMode = .ScaleAspectFit
    }
}
Motine
fuente
-1

Tuve el mismo problema, pero no pude hacerlo funcionar (tal vez sea un error con el SDK).

Finalmente, como solución, coloqué un UIImageViewdetrás de mi botón y configuré las opciones que quería en eso, luego simplemente coloqué un espacio UIButtonen blanco encima.

Anshu Chimala
fuente
7
¿Hay un eco aquí? ;-)
Dan Ray