2010-03-25 10 views
102

Tengo un UIButton con el texto "Explorar la aplicación" y UIImage (>) En Interface Builder que parece:iPhone UIButton - posición de la imagen

[ (>) Explore the app ] 

Pero necesito colocar este UIImage después del texto:

[ Explore the app (>) ] 

¿Cómo puedo mover el UIImage a la derecha?

+0

También puede usar Interface Builder. Mira mi respuesta aquí: http://stackoverflow.com/questions/2765024/how-to-set-the-title-as-left-alignment-in-the-uibutton/22725345#22725345 – n8tr

+0

Solo usa esta subclase con algunas filas de código: https://github.com/k06a/RTLButton – k06a

Respuesta

1

Forzar 'de derecha a izquierda' para el botón no es una opción si su aplicación admite tanto 'de izquierda a derecha' como 'de derecha a izquierda'.

La solución que funcionó para mí es una subclase que se puede agregar al botón en el guión gráfico y funciona bien con limitaciones (probado en IOS 11):

class ButtonWithImageAtEnd: UIButton { 

    override func layoutSubviews() { 
     super.layoutSubviews() 

     if let imageView = imageView, let titleLabel = titleLabel { 
      let padding: CGFloat = 15 
      imageEdgeInsets = UIEdgeInsets(top: 5, left: titleLabel.frame.size.width+padding, bottom: 5, right: -titleLabel.frame.size.width-padding) 
      titleEdgeInsets = UIEdgeInsets(top: 0, left: -imageView.frame.width, bottom: 0, right: imageView.frame.width) 
     } 

    } 

} 

Donde 'padding' sería el espacio entre el título y la imagen.

83

Configure imageEdgeInset y titleEdgeInset para mover los componentes dentro de su imagen. También puede crear un botón utilizando esos gráficos que es de tamaño completo y usarlo como la imagen de fondo para el botón (luego use titleEdgeInsets para mover el título).

+1

¡Esto es genial! ¡Gracias! –

+8

Es mucho menos código simplemente configurar las inserciones que implementar una subclase. Este es el objetivo de las inserciones. La manipulación de marcos para vistas secundarias (que no ha creado) se siente más como un truco. –

+6

@kimsnarf, ¿en serio? ¿Es mucho menos trabajo (y * menos * de un truco) modificar las inserciones cada vez que realizas un pequeño cambio en el tamaño de la imagen o en la longitud del título? –

30

¿Qué pasa con la subclase UIButton y la anulación layoutSubviews?

Entonces post-procesamiento de los lugares de la respuesta de self.imageView & self.titleLabel

+4

Esto es mucho más fácil que todos los otros consejos (como el anterior) sobre tratar de colocar todo correctamente usando insertos sintonizados a mano. –

53

Raymond W es mejor aquí. Subclase UIButton con diseño personalizadoSubviews. Muy sencillo de hacer, he aquí una aplicación layoutSubviews que trabajó para mí:

- (void)layoutSubviews 
{ 
    // Allow default layout, then adjust image and label positions 
    [super layoutSubviews]; 

    UIImageView *imageView = [self imageView]; 
    UILabel *label = [self titleLabel]; 

    CGRect imageFrame = imageView.frame; 
    CGRect labelFrame = label.frame; 

    labelFrame.origin.x = imageFrame.origin.x; 
    imageFrame.origin.x = labelFrame.origin.x + CGRectGetWidth(labelFrame); 

    imageView.frame = imageFrame; 
    label.frame = labelFrame; 
} 
+2

De esta manera es mejor en el caso de que necesite administrar muchos botones, pero necesito cambiar solo un botón :) –

+2

Si la imagen del botón es nula, la etiqueta se extravió, probablemente porque el UIImageView no está insertado (Probado en iOS6.0) Debería considerar editar marcos solo si imageView.image no es nulo. – Scakko

+2

Sugeriría la siguiente mejora en esta respuesta, de modo que ambas vistas permanezcan centradas: 'CGFloat cumulativeWidth = CGRectGetWidth (imageFrame) + CGRectGetWidth (labelFrame) + 10; CGFloat excessiveWidth = CGRectGetWidth (self.bounds) - cumulativeWidth; labelFrame.origin.x = excessiveWidth/2; imageFrame.origin.x = CGRectGetMaxX (labelFrame) + 10; ' –

2
// Get the size of the text and image 
CGSize buttonLabelSize = [[self.button titleForState:UIControlStateNormal] sizeWithFont:self.button.titleLabel.font]; 
CGSize buttonImageSize = [[self.button imageForState:UIControlStateNormal] size]; 

// You can do this line in the xib too: 
self.button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight; 

// Adjust Edge Insets according to the above measurement. The +2 adds a little space 
self.button.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, -(buttonLabelSize.width+2)); 
self.button.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, buttonImageSize.width+2); 

Esto crea un botón alineado a la derecha, así:

[   button label (>)] 

El botón no se ajusta es el ancho de acuerdo con el contexto, de modo que el espacio aparecerá a la izquierda de la etiqueta. Puede resolver esto calculando el ancho del marco del botón desde el botón LabelSize.width y el buttonImageSize.width.

151

Mi solución a esto es bastante simple

[button sizeToFit]; 
button.titleEdgeInsets = UIEdgeInsetsMake(0, -button.imageView.frame.size.width, 0, button.imageView.frame.size.width); 
button.imageEdgeInsets = UIEdgeInsetsMake(0, button.titleLabel.frame.size.width, 0, -button.titleLabel.frame.size.width); 
+4

¡Esto funciona genial! Es difícil entender el concepto de borde insertado. ¿Alguna idea de por qué tenemos que configurar el borde izquierdo y derecho? Teóricamente, si muevo el título a la izquierda y la imagen a la derecha, eso sería suficiente. ¿Por qué tengo que configurar tanto a la izquierda como a la derecha? –

+3

LA MEJOR SOLUCIÓN QUE HE ENCONTRADO – Bimawa

+2

Esta respuesta funciona perfectamente. La respuesta aceptada es correcta y apunta a los documentos API correctos, pero esta es la solución de copiar y pegar para hacer lo que el OP solicitó. – mclaughlinj

4

La construcción de la respuesta por @split ...

La respuesta es fantástica, pero no tiene en cuenta el hecho de que el botón puede tener la imagen personalizada y inserciones de borde de título que se establecen de antemano (por ejemplo, en el guión gráfico).

Por ejemplo, es posible que desee que la imagen tenga un relleno de la parte superior e inferior del contenedor, pero aún mueva la imagen hacia el lado derecho del botón.

me extendió el concepto con este método: -

- (void) moveImageToRightSide { 
    [self sizeToFit]; 

    CGFloat titleWidth = self.titleLabel.frame.size.width; 
    CGFloat imageWidth = self.imageView.frame.size.width; 
    CGFloat gapWidth = self.frame.size.width - titleWidth - imageWidth; 
    self.titleEdgeInsets = UIEdgeInsetsMake(self.titleEdgeInsets.top, 
              -imageWidth + self.titleEdgeInsets.left, 
              self.titleEdgeInsets.bottom, 
              imageWidth - self.titleEdgeInsets.right); 

    self.imageEdgeInsets = UIEdgeInsetsMake(self.imageEdgeInsets.top, 
              titleWidth + self.imageEdgeInsets.left + gapWidth, 
              self.imageEdgeInsets.bottom, 
              -titleWidth + self.imageEdgeInsets.right - gapWidth); 
} 
4

en Swift:

override func layoutSubviews() 
{ 
    super.layoutSubviews() 

    var imageFrame = self.imageView?.frame; 
    var labelFrame = self.titleLabel?.frame; 

    let inset: CGFloat = 5 

    if var imageFrame = imageFrame 
    { 
     if var labelFrame = labelFrame 
     { 
      let cumulativeWidth = imageFrame.width + labelFrame.width + inset 
      let excessiveWidth = self.bounds.width - cumulativeWidth 
      labelFrame.origin.x = excessiveWidth/2 
      imageFrame.origin.x = labelFrame.origin.x + labelFrame.width + inset 

      self.imageView?.frame = imageFrame 
      self.titleLabel?.frame = labelFrame 
     } 
    } 
} 
94

En IOS 9 en adelante, parece que una forma sencilla de lograr esto es para obligar a la semántica de la vista.

enter image description here

o mediante programación, usando:

button.semanticContentAttribute = .ForceRightToLeft 
+0

wonderful ans +1 – Vvk

+1

Por mucho que me haya gustado tu respuesta (+1), odio decir que podría no ser la forma "correcta" de hacerlo, pero es una de las más fáciles. – farzadshbfn

+0

@farzadshbfn tienes razón. Cambié esa palabra por "simple", parece más consistente. – Alvivi

0
button.semanticContentAttribute = UISemanticContentAttributeForceRightToLeft; 
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight; 
9

Otra manera simple (que no es iOS 9 solamente) es una subclase UIButton para anular estos dos métodos

override func titleRectForContentRect(contentRect: CGRect) -> CGRect { 
    var rect = super.titleRectForContentRect(contentRect) 
    rect.origin.x = 0 
    return rect 
} 

override func imageRectForContentRect(contentRect: CGRect) -> CGRect { 
    var rect = super.imageRectForContentRect(contentRect) 
    rect.origin.x = CGRectGetMaxX(contentRect) - CGRectGetWidth(rect) 
    return rect 
} 

contentEdgeInsets ya se ha tenido en cuenta al usar super.

+0

Gracias! Me gusta mucho más que las respuestas que subclasan y anulan el layoutSubviews() :) –

+1

La mejor manera de hacerlo en mi humilde opinión :) – DrPatience

0

esta solución funciona iOS 7 y superior

Sólo subclase UIButton

@interface UIButton (Image) 

- (void)swapTextWithImage; 

@end 

@implementation UIButton (Image) 

- (void)swapTextWithImage { 
    const CGFloat kDefaultPadding = 6.0f; 
    CGSize buttonSize = [self.titleLabel.text sizeWithAttributes:@{ 
                   NSFontAttributeName:self.titleLabel.font 
                   }]; 

    self.titleEdgeInsets = UIEdgeInsetsMake(0, -self.imageView.frame.size.width, 0, self.imageView.frame.size.width); 
    self.imageEdgeInsets = UIEdgeInsetsMake(0, buttonSize.width + kDefaultPadding, 0, -buttonSize.width); 
} 

@end 

Uso (En algún lugar de su clase):

[self.myButton setTitle:@"Any text" forState:UIControlStateNormal]; 
[self.myButton swapTextWithImage]; 
0

Sobre la base de las respuestas anteriores. Si desea tener un margen entre el icono y el título del botón, el código tiene que cambiar un poco para evitar que la etiqueta y el icono floten por encima de los límites de los botones de tamaño intrínseco.

let margin = CGFloat(4.0) 
button.titleEdgeInsets = UIEdgeInsetsMake(0, -button.imageView.frame.size.width, 0, button.imageView.frame.size.width); 
button.imageEdgeInsets = UIEdgeInsetsMake(0, button.titleLabel.frame.size.width, 0, -button.titleLabel.frame.size.width) 
button.contentEdgeInsets = UIEdgeInsetsMake(0, margin, 0, margin) 

La última línea de código es importante para el cálculo de tamaño de contenido intrínsecamente para el diseño automático.

Cuestiones relacionadas