Diseño automático: el tamaño intrínseco del UIButton no incluye inserciones de título


Si tengo un UIButton dispuesto usando autolayout, su tamaño se ajusta muy bien para adaptarse a su contenido.

Si establezco una imagen como button.image, el tamaño instrinsic de nuevo parece explicar esto.

Sin embargo, si retoco el titleEdgeInsets del botón, el diseño no tiene en cuenta esto y en su lugar trunca el título del botón.

¿Cómo puedo asegurar que el ancho intrínseco del botón tenga en cuenta el recuadro?

introduzca la descripción de la imagen aquí

Editar:

Estoy usando el siguiente:

[self.backButton setTitleEdgeInsets:UIEdgeInsetsMake(0, 5, 0, 0)];

El objetivo es añadir cierta separación entre la imagen y el texto.

Author: Astoria, 2013-07-23

11 answers

Puede resolver esto sin tener que anular ningún método o establecer una restricción de ancho arbitraria. Puede hacerlo todo en Interface Builder de la siguiente manera.

  • El ancho intrínseco del botón se deriva del ancho del título más el ancho del icono más las inserciones de borde izquierda y derecha content.

  • Si un botón tiene tanto una imagen como un texto, están centrados como un grupo, sin relleno entre ellos.

  • Si agregas un recuadro de contenido izquierdo, se calcula relativo al texto, no al texto + icono.

  • Si establece un recuadro negativo de imagen izquierda, la imagen se extrae hacia la izquierda, pero el ancho total del botón no se ve afectado.

  • Si establece un recuadro negativo de imagen izquierda, el diseño real utiliza la mitad de ese valor. Por lo tanto, para obtener un recuadro izquierdo de -20 puntos, debe usar un valor de recuadro izquierdo de -40 puntos en Interface Builder.

Por lo tanto, proporciona un recuadro de contenido izquierdo lo suficientemente grande como para crear espacio tanto para el recuadro izquierdo deseado y el relleno interno entre el icono y el texto, y luego cambia el icono a la izquierda duplicando la cantidad de relleno que quieras entre el icono y el texto. El resultado es un botón con inserciones de contenido iguales a izquierda y derecha, y un par de texto e iconos que se centran como un grupo, con una cantidad específica de relleno entre ellos.

Algunos valores de ejemplo:

// Produces a button with the layout:
// |-20-icon-10-text-20-|
// AutoLayout intrinsic width works as you'd desire.
button.contentEdgeInsets = UIEdgeInsetsMake(10, 30, 10, 20)
button.imageEdgeInsets = UIEdgeInsetsMake(0, -20, 0, 0)
 126
Author: jaredsinclair,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-13 20:32:03

Puede hacer que esto funcione en Interface Builder (sin escribir ningún código), utilizando una combinación de Títulos negativos y positivos e Inserciones de Contenido.

introduzca la descripción de la imagen aquí

Actualizar: Xcode 7 tiene un error en el que no puede ingresar valores negativos en el campo de inserción Right, pero puede usar el control paso a paso al lado para disminuir el valor. (Gracias Stuart)

Hacer esto agregará 8pt de espaciado entre la imagen y el título y aumentará el ancho intrínseco del botón por la misma cantidad. Así:

introduzca la descripción de la imagen aquí

 164
Author: n.Drake,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-22 10:01:51

¿Por qué no anular el método intrinsicContentSize en UIView? Por ejemplo:

- (CGSize) intrinsicContentSize
{
    CGSize s = [super intrinsicContentSize];

    return CGSizeMake(s.width + self.titleEdgeInsets.left + self.titleEdgeInsets.right,
                      s.height + self.titleEdgeInsets.top + self.titleEdgeInsets.bottom);
}

Esto debería indicarle al sistema de diseño automático que debería aumentar el tamaño del botón para permitir las inserciones y mostrar el texto completo. No estoy en mi propia computadora, así que no he probado esto.

 90
Author: Maarten,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-22 12:57:11

No ha especificado cómo está configurando las inserciones, así que supongo que está utilizando titleEdgeInsets porque veo el mismo efecto que está obteniendo. Si uso contentEdgeInsets en su lugar funciona correctamente.

- (IBAction)ChangeTitle:(UIButton *)sender {
    self.button.contentEdgeInsets = UIEdgeInsetsMake(0,20,0,20);
    [self.button setTitle:@"Long Long Title" forState:UIControlStateNormal];
}
 82
Author: rdelmar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-23 03:06:26

Este hilo es un poco viejo, pero me encontré con esto yo mismo y pude resolverlo usando una inserción negativa. Por ejemplo, sustituya los valores de relleno deseados aquí:

UIButton* myButton = [[UIButton alloc] init];
// setup some autolayout constraints here
myButton.titleEdgeInsets = UIEdgeInsetsMake(-desiredBottomPadding,
                                            -desiredRightPadding,
                                            -desiredTopPadding,
                                            -desiredLeftPadding);

Combinado con las restricciones de diseño automático correctas, se termina con un botón de cambio de tamaño automático que contiene una imagen y texto! Visto a continuación con desiredLeftPadding establecido en 10.

Botón con imagen y texto corto

Botón con imagen y texto largo

Se puede ver que el real marco del botón no abarca la etiqueta (ya que la etiqueta se desplaza 10 puntos a la derecha, fuera de los límites), pero hemos logrado 10 puntos de relleno entre el texto y la imagen.

 18
Author: Brian Gerstle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-18 02:50:58

Y para Swift funcionó esto:

extension UIButton {
    override open var intrinsicContentSize: CGSize {
        let intrinsicContentSize = super.intrinsicContentSize

        let adjustedWidth = intrinsicContentSize.width + titleEdgeInsets.left + titleEdgeInsets.right
        let adjustedHeight = intrinsicContentSize.height + titleEdgeInsets.top + titleEdgeInsets.bottom

        return CGSize(width: adjustedWidth, height: adjustedHeight)
    }
}

Love U Swift

 14
Author: pegpeg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-29 02:18:21

Todo lo anterior no funcionó para iOS 9 + , lo que hice fue:

  • Agregue una restricción de ancho (para un ancho mínimo cuando el botón no tiene texto. El botón escalará automáticamente si se proporciona texto)
  • establecer la relación a Mayor o Igual

introduzca la descripción de la imagen aquí

Ahora para agregar un borde alrededor del botón simplemente use el método:

button.contentEdgeInsets = UIEdgeInsetsMake(0,20,0,20);
 7
Author: Oritm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-07 12:43:30

Para Swift 3 basado en la respuesta de pegpeg :

extension UIButton {

    override open var intrinsicContentSize: CGSize {

        let intrinsicContentSize = super.intrinsicContentSize

        let adjustedWidth = intrinsicContentSize.width + titleEdgeInsets.left + titleEdgeInsets.right
        let adjustedHeight = intrinsicContentSize.height + titleEdgeInsets.top + titleEdgeInsets.bottom

        return CGSize(width: adjustedWidth, height: adjustedHeight)

    }

}
 6
Author: TheoK,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-10 13:24:06

La opción también está disponible en interface builder. Ver el recuadro. Puse izquierda y derecha a 3. Funciona como un encanto.

Interfaz builder captura de pantalla

 3
Author: zeiteisen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-03 14:26:02

Quería añadir un espacio de 5pt entre mi icono de UIButton y la etiqueta. Así es como lo logré:

UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeCustom];
// more button config etc
infoButton.contentEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 5);
infoButton.titleEdgeInsets = UIEdgeInsetsMake(0, 5, 0, -5);

La forma en que contentEdgeInsets, titleEdgeInsets y imageEdgeInsets se relacionan entre sí requiere un poco de toma y daca de cada recuadro. Por lo tanto, si agregas algunas inserciones a la izquierda del título, debes agregar una inserción negativa a la derecha y proporcionar un poco más de espacio (a través de una inserción positiva) en el contenido a la derecha.

Añadiendo un recuadro de contenido correcto para que coincida con el desplazamiento del título inserta mi texto no va fuera de los límites del botón.

 2
Author: orj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-19 07:36:46

La solución que uso es agregar una restricción de ancho al botón. Luego, en algún lugar de la inicialización, después de establecer el texto, actualice la restricción de ancho de la siguiente manera:

self.buttonWidthConstraint.constant = self.shareButton.intrinsicContentSize.width + 8;

Donde 8 es cualquiera que sea su recuadro.

 1
Author: Bob Spryn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-29 06:00:23