Saltar al contenido

Alineación de texto e imagen en UIButton con imageEdgeInsets y titleEdgeInsets

Solución:

Llego un poco tarde a esta fiesta, pero creo que tengo algo útil que agregar.

La respuesta de Kekoa es genial pero, como menciona RonLugge, puede hacer que el botón ya no respete sizeToFit o, lo que es más importante, puede hacer que el botón recorte su contenido cuando tiene un tamaño intrínseco. ¡Ay!

Primero, sin embargo,

Una breve explicación de cómo creo imageEdgeInsets y titleEdgeInsets trabaja:

Los documentos para imageEdgeInsets tener lo siguiente para decir, en parte:

Utilice esta propiedad para cambiar el tamaño y reposicionar el rectángulo de dibujo efectivo para la imagen del botón. Puede especificar un valor diferente para cada uno de los cuatro recuadros (arriba, izquierda, abajo, derecha). Un valor positivo encoge, o inserta, ese borde, acercándolo al centro del botón. Un valor negativo expande o contrarresta esa ventaja.

Creo que esta documentación se escribió imaginando que el botón no tiene título, solo una imagen. Tiene mucho más sentido pensar de esta manera, y se comporta como UIEdgeInsets normalmente lo hago. Básicamente, el marco de la imagen (o el título, con titleEdgeInsets) se mueve hacia adentro para inserciones positivas y hacia afuera para inserciones negativas.

¿OK y eso qué?

¡Estoy llegando! Esto es lo que tiene por defecto, configurando una imagen y un título (el borde del botón es verde solo para mostrar dónde está):

Imagen inicial;  sin espacio entre el título y la imagen.

Cuando desee espaciar una imagen y un título, sin que ninguno de los dos se aplaste, debe establecer cuatro inserciones diferentes, dos en cada una de la imagen y el título. Eso es porque no quieres cambiar el tamaños de los marcos de esos elementos, pero solo sus posiciones. Cuando empiezas a pensar de esta manera, el cambio necesario a la categoría excelente de Kekoa queda claro:

@implementation UIButton(ImageTitleCentering)

- (void)centerButtonAndImageWithSpacing:(CGFloat)spacing {
    CGFloat insetAmount = spacing / 2.0;
    self.imageEdgeInsets = UIEdgeInsetsMake(0, -insetAmount, 0, insetAmount);
    self.titleEdgeInsets = UIEdgeInsetsMake(0, insetAmount, 0, -insetAmount);
}

@end

Pero espera, tu dices, cuando hago eso, obtengo esto:

El espaciado es bueno, pero la imagen y el título están fuera del marco de la vista.

¡Oh sí! Lo olvidé, los médicos me advirtieron sobre esto. Dicen, en parte:

Esta propiedad se utiliza solo para colocar la imagen durante el diseño. El botón no usa esta propiedad para determinar intrinsicContentSize y sizeThatFits:.

Pero hay es una propiedad que puede ayudar, y eso es contentEdgeInsets. Los documentos para eso dicen, en parte:

El botón utiliza esta propiedad para determinar intrinsicContentSize y sizeThatFits:.

Eso suena bien. Así que modifiquemos la categoría una vez más:

@implementation UIButton(ImageTitleCentering)

- (void)centerButtonAndImageWithSpacing:(CGFloat)spacing {
    CGFloat insetAmount = spacing / 2.0;
    self.imageEdgeInsets = UIEdgeInsetsMake(0, -insetAmount, 0, insetAmount);
    self.titleEdgeInsets = UIEdgeInsetsMake(0, insetAmount, 0, -insetAmount);
    self.contentEdgeInsets = UIEdgeInsetsMake(0, insetAmount, 0, insetAmount);
}

@end

¿Y qué obtienes?

El espaciado y el marco ahora son correctos.

Me parece un ganador.


¿Trabaja en Swift y no quiere pensar en absoluto? Aquí está la versión final de la extensión en Swift:

extension UIButton {
    func centerTextAndImage(spacing: CGFloat) {
        let insetAmount = spacing / 2
        imageEdgeInsets = UIEdgeInsets(top: 0, left: -insetAmount, bottom: 0, right: insetAmount)
        titleEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: -insetAmount)
        contentEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: insetAmount)
    }
}

Acepto la documentación sobre imageEdgeInsets y titleEdgeInsets debería ser mejor, pero descubrí cómo obtener la posición correcta sin recurrir a prueba y error.

La idea general está aquí en esta pregunta, pero eso es si desea que el texto y la imagen estén centrados. No queremos que la imagen y el texto se centren individualmente, queremos que la imagen y el texto estén centrados juntos como una sola entidad. De hecho, esto es lo que UIButton ya hace, por lo que simplemente necesitamos ajustar el espaciado.

CGFloat spacing = 10; // the amount of spacing to appear between image and title
tabBtn.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, spacing);
tabBtn.titleEdgeInsets = UIEdgeInsetsMake(0, spacing, 0, 0);

También convertí esto en una categoría para UIButton para que sea fácil de usar:

UIButton + Posición.h

@interface UIButton(ImageTitleCentering)

-(void) centerButtonAndImageWithSpacing:(CGFloat)spacing;

@end

UIButton + Posición.m

@implementation UIButton(ImageTitleCentering)

-(void) centerButtonAndImageWithSpacing:(CGFloat)spacing {
    self.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, spacing);
    self.titleEdgeInsets = UIEdgeInsetsMake(0, spacing, 0, 0);
}

@end

Así que ahora todo lo que tengo que hacer es:

[button centerButtonAndImageWithSpacing:10];

Y obtengo lo que necesito cada vez. No más problemas con las inserciones de los bordes manualmente.

EDITAR: Intercambiar imagen y texto

En respuesta a @Javal en comentarios

Usando este mismo mecanismo, podemos intercambiar la imagen y el texto. Para realizar el intercambio, simplemente use un espacio negativo pero también incluya el ancho del texto y la imagen. Esto requerirá que los marcos sean conocidos y el diseño ya realizado.

[self.view layoutIfNeeded];
CGFloat flippedSpacing = -(desiredSpacing + button.currentImage.size.width + button.titleLabel.frame.size.width);
[button centerButtonAndImageWithSpacing:flippedSpacing];

Por supuesto, probablemente querrá hacer un buen método para esto, potencialmente agregando un método de segunda categoría, esto se deja como un ejercicio para el lector.

Además, si quieres hacer algo similar a

ingrese la descripción de la imagen aquí

Necesitas

1.Configure la alineación horizontal y vertical para el botón

ingrese la descripción de la imagen aquí

  1. Encuentre todos los valores requeridos y establezca UIImageEdgeInsets

            CGSize buttonSize = button.frame.size;
            NSString *buttonTitle = button.titleLabel.text;
            CGSize titleSize = [buttonTitle sizeWithAttributes:@{ NSFontAttributeName : [UIFont camFontZonaProBoldWithSize:12.f] }];
            UIImage *buttonImage = button.imageView.image;
            CGSize buttonImageSize = buttonImage.size;
    
            CGFloat offsetBetweenImageAndText = 10; //vertical space between image and text
    
            [button setImageEdgeInsets:UIEdgeInsetsMake((buttonSize.height - (titleSize.height + buttonImageSize.height)) / 2 - offsetBetweenImageAndText,
                                                        (buttonSize.width - buttonImageSize.width) / 2,
                                                        0,0)];                
            [button setTitleEdgeInsets:UIEdgeInsetsMake((buttonSize.height - (titleSize.height + buttonImageSize.height)) / 2 + buttonImageSize.height + offsetBetweenImageAndText,
                                                        titleSize.width + [button imageEdgeInsets].left > buttonSize.width ? -buttonImage.size.width  +  (buttonSize.width - titleSize.width) / 2 : (buttonSize.width - titleSize.width) / 2 - buttonImage.size.width,
                                                        0,0)];
    

Esto organizará su título e imagen en el botón.

También tenga en cuenta que actualice esto en cada retransmisión


Rápido

import UIKit

extension UIButton {
    // MARK: - UIButton+Aligment

    func alignContentVerticallyByCenter(offset:CGFloat = 10) {
        let buttonSize = frame.size

        if let titleLabel = titleLabel,
            let imageView = imageView {

            if let buttonTitle = titleLabel.text,
                let image = imageView.image {
                let titleString:NSString = NSString(string: buttonTitle)
                let titleSize = titleString.sizeWithAttributes([
                    NSFontAttributeName : titleLabel.font
                    ])
                let buttonImageSize = image.size

                let topImageOffset = (buttonSize.height - (titleSize.height + buttonImageSize.height + offset)) / 2
                let leftImageOffset = (buttonSize.width - buttonImageSize.width) / 2
                imageEdgeInsets = UIEdgeInsetsMake(topImageOffset,
                                                   leftImageOffset,
                                                   0,0)

                let titleTopOffset = topImageOffset + offset + buttonImageSize.height
                let leftTitleOffset = (buttonSize.width - titleSize.width) / 2 - image.size.width

                titleEdgeInsets = UIEdgeInsetsMake(titleTopOffset,
                                                   leftTitleOffset,
                                                   0,0)
            }
        }
    }
}
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *