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á):
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:
¡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
ysizeThatFits:
.
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
ysizeThatFits:
.
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?
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
Necesitas
1.Configure la alineación horizontal y vertical para el botón
-
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)
}
}
}
}