titlelabel guidelines color buttons iphone ios uibutton uikit

iphone - guidelines - Alinear texto e imagen en UIButton con imageEdgeInsets y titleEdgeInsets



menu ios (12)

En Xcode 8.0 , simplemente puede hacerlo cambiando las insets en inspector de tamaño.

Seleccione el UIButton -> Inspector de atributos -> vaya a inspector de tamaño y modifique las inserciones de contenido, imagen y título.

Y si desea cambiar la imagen en el lado derecho, simplemente puede cambiar la propiedad semántica a Force Right-to-left en el inspector de atributos.

Me gustaría colocar un icono a la izquierda de las dos líneas de texto, de manera que haya aproximadamente 2-3 píxeles de espacio entre la imagen y el inicio del texto. El control en sí está alineado en el centro horizontalmente (establecido a través de Interface Builder)

El botón se asemejaría a algo como esto:

| | |[Image] Add To | | Favorites |

Estoy intentando configurar esto con contentEdgeInset, imageEdgeInsets y titleEdgeInsets en vano. Entiendo que un valor negativo expande el borde mientras que un valor positivo lo reduce para acercarlo al centro.

Lo intenté:

[button setTitleEdgeInsets:UIEdgeInsetsMake(0, -image.size.width, 0, 0)]; [button setImageEdgeInsets:UIEdgeInsetsMake(0, button.titleLabel.bounds.size.width, 0, 0)];

pero esto no lo muestra correctamente. He estado ajustando los valores, pero al pasar de, digamos, -5 a -10 en el valor de inserción izquierdo, no parece que se mueva de la manera esperada. -10 moverá el texto completamente hacia la izquierda, así que esperaba que -5 lo hiciera a la mitad del lado izquierdo, pero no lo hace.

¿Cuál es la lógica detrás de las inserciones? No estoy familiarizado con la colocación de imágenes y la terminología relacionada.

Utilicé esta pregunta SO como referencia, pero algo acerca de mis valores no está bien. UIButton: ¿cómo centrar una imagen y un texto usando imageEdgeInsets y titleEdgeInsets?


En la interfaz Builder. Seleccione el UIButton -> Inspector de atributos -> Borde = Título y modifique las inserciones de borde


Este es un ejemplo simple de cómo usar imageEdgeInsets. Esto hará que un botón 30x30 con un área de golpeo sea 10 píxeles más grande en todos los sentidos (50x50)

var expandHittableAreaAmt : CGFloat = 10 var buttonWidth : CGFloat = 30 var button = UIButton.buttonWithType(UIButtonType.Custom) as UIButton button.frame = CGRectMake(0, 0, buttonWidth+expandHittableAreaAmt, buttonWidth+expandHittableAreaAmt) button.imageEdgeInsets = UIEdgeInsetsMake(expandHittableAreaAmt, expandHittableAreaAmt, expandHittableAreaAmt, expandHittableAreaAmt) button.setImage(UIImage(named: "buttonImage"), forState: .Normal) button.addTarget(self, action: "didTouchButton:", forControlEvents:.TouchUpInside)


Estoy de acuerdo en que la documentación sobre imageEdgeInsets y titleEdgeInsets debería ser mejor, pero me di cuenta de cómo obtener la posición correcta sin recurrir a prueba y error.

La idea general está aquí en esta pregunta , pero eso era si deseaba que el texto y la imagen estuvieran centrados. No queremos que la imagen y el texto se centren individualmente, queremos que la imagen y el texto se centren juntos como una sola entidad. De hecho, esto es lo que hace UIButton, 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, por lo que será fácil de usar:

UIButton + Position.h

@interface UIButton(ImageTitleCentering) -(void) centerButtonAndImageWithSpacing:(CGFloat)spacing; @end

UIButton + Position.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 consigo lo que necesito cada vez. No más lío con las inserciones de borde manualmente.

EDITAR: Intercambiar imagen y texto

En respuesta a @Javal en comentarios.

Usando este mismo mecanismo, podemos intercambiar la imagen y el texto. Para lograr el intercambio, simplemente use un espacio negativo, pero también incluya el ancho del texto y la imagen. Esto requerirá que se conozcan los marcos y que el diseño ya esté 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, posiblemente agregando un método de segunda categoría, esto se deja como un ejercicio para el lector.


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

La respuesta de Kekoa es excelente, 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 sizeToFit su contenido cuando tiene un tamaño intrínseco. ¡Ay!

Primero, sin embargo,

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

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

Utilice esta propiedad para cambiar el tamaño y la posición del rectángulo de dibujo efectivo para la imagen del botón. Puede especificar un valor diferente para cada una de las cuatro inserciones (superior, izquierda, inferior, derecha). Un valor positivo reduce, o inserta, ese borde, acercándolo al centro del botón. Un valor negativo expande, o supera, esa ventaja.

Creo que esta documentación fue escrita 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 lo UIEdgeInsets generalmente UIEdgeInsets . 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 el espacio entre una imagen y un título, sin causar que se aplasten, debe configurar cuatro inserciones diferentes, dos en cada una de las imágenes y títulos. Esto se debe a que no desea cambiar el tamaño de los marcos de esos elementos, sino solo sus posiciones. Cuando empiezas a pensar de esta manera, el cambio necesario a la excelente categoría de Kekoa se hace evidente:

@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 , dices, cuando hago eso, obtengo esto:

¡Oh si! Lo olvidé, los doctores me advirtieron sobre esto. Dicen, en parte:

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

Pero hay una propiedad que puede ayudar, y 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 vamos a ajustar 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 que obtienes

Parece un ganador para mí.

¿Trabajando en Swift y no quiero 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) } }


Puedes evitar muchos problemas usando esto.

myButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; myButton.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;

Esto alineará todo tu contenido automáticamente a la izquierda (o donde quieras)

Swift 3:

myButton.contentHorizontalAlignment = UIControlContentHorizontalAlignment.left; myButton.contentVerticalAlignment = UIControlContentVerticalAlignment.center;


También llego un poco tarde a esta fiesta, pero creo que tengo algo útil que agregar: o).

UIButton una subclase UIButton cuyo propósito es poder elegir dónde se UIButton la imagen del botón, ya sea vertical u horizontalmente.

Significa que puedes hacer este tipo de botones:

Aquí los detalles sobre cómo crear estos botones con mi clase:

func makeButton (imageVerticalAlignment:LayoutableButton.VerticalAlignment, imageHorizontalAlignment:LayoutableButton.HorizontalAlignment, title:String) -> LayoutableButton { let button = LayoutableButton () button.imageVerticalAlignment = imageVerticalAlignment button.imageHorizontalAlignment = imageHorizontalAlignment button.setTitle(title, for: .normal) // add image, border, ... return button } let button1 = makeButton(imageVerticalAlignment: .center, imageHorizontalAlignment: .left, title: "button1") let button2 = makeButton(imageVerticalAlignment: .center, imageHorizontalAlignment: .right, title: "button2") let button3 = makeButton(imageVerticalAlignment: .top, imageHorizontalAlignment: .center, title: "button3") let button4 = makeButton(imageVerticalAlignment: .bottom, imageHorizontalAlignment: .center, title: "button4") let button5 = makeButton(imageVerticalAlignment: .bottom, imageHorizontalAlignment: .center, title: "button5") button5.contentEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)

Para hacer eso, agregué 2 atributos: imageVerticalAlignment y imageHorizontalAlignment . Por supuesto, si su botón solo tiene una imagen o un título ... ¡no use esta clase en absoluto!

También agregué un atributo llamado imageToTitleSpacing que te permite ajustar el espacio entre el título y la imagen.

Esta clase hace todo lo posible por ser compatible si desea usar imageEdgeInsets , titleEdgeInsets y contentEdgeInsets directamente o en combinación con los nuevos atributos de diseño.

Como nos lo explica @ravron, hago todo lo posible para que el borde del contenido del botón sea correcto (como puede ver con los bordes rojos).

También puedes usarlo en Interface Builder:

  1. Crear un UIButton
  2. Cambiar la clase de botón
  3. Ajuste los atributos de diseño con "centro", "arriba", "abajo", "izquierda" o "derecha"

Aquí el código ( gist ):

@IBDesignable class LayoutableButton: UIButton { enum VerticalAlignment : String { case center, top, bottom, unset } enum HorizontalAlignment : String { case center, left, right, unset } @IBInspectable var imageToTitleSpacing: CGFloat = 8.0 { didSet { setNeedsLayout() } } var imageVerticalAlignment: VerticalAlignment = .unset { didSet { setNeedsLayout() } } var imageHorizontalAlignment: HorizontalAlignment = .unset { didSet { setNeedsLayout() } } @available(*, unavailable, message: "This property is reserved for Interface Builder. Use ''imageVerticalAlignment'' instead.") @IBInspectable var imageVerticalAlignmentName: String { get { return imageVerticalAlignment.rawValue } set { if let value = VerticalAlignment(rawValue: newValue) { imageVerticalAlignment = value } else { imageVerticalAlignment = .unset } } } @available(*, unavailable, message: "This property is reserved for Interface Builder. Use ''imageHorizontalAlignment'' instead.") @IBInspectable var imageHorizontalAlignmentName: String { get { return imageHorizontalAlignment.rawValue } set { if let value = HorizontalAlignment(rawValue: newValue) { imageHorizontalAlignment = value } else { imageHorizontalAlignment = .unset } } } var extraContentEdgeInsets:UIEdgeInsets = UIEdgeInsets.zero override var contentEdgeInsets: UIEdgeInsets { get { return super.contentEdgeInsets } set { super.contentEdgeInsets = newValue self.extraContentEdgeInsets = newValue } } var extraImageEdgeInsets:UIEdgeInsets = UIEdgeInsets.zero override var imageEdgeInsets: UIEdgeInsets { get { return super.imageEdgeInsets } set { super.imageEdgeInsets = newValue self.extraImageEdgeInsets = newValue } } var extraTitleEdgeInsets:UIEdgeInsets = UIEdgeInsets.zero override var titleEdgeInsets: UIEdgeInsets { get { return super.titleEdgeInsets } set { super.titleEdgeInsets = newValue self.extraTitleEdgeInsets = newValue } } //Needed to avoid IB crash during autolayout override init(frame: CGRect) { super.init(frame: frame) } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) self.imageEdgeInsets = super.imageEdgeInsets self.titleEdgeInsets = super.titleEdgeInsets self.contentEdgeInsets = super.contentEdgeInsets } override func layoutSubviews() { if let imageSize = self.imageView?.image?.size, let font = self.titleLabel?.font, let textSize = self.titleLabel?.attributedText?.size() ?? self.titleLabel?.text?.size(attributes: [NSFontAttributeName: font]) { var _imageEdgeInsets = UIEdgeInsets.zero var _titleEdgeInsets = UIEdgeInsets.zero var _contentEdgeInsets = UIEdgeInsets.zero let halfImageToTitleSpacing = imageToTitleSpacing / 2.0 switch imageVerticalAlignment { case .bottom: _imageEdgeInsets.top = (textSize.height + imageToTitleSpacing) / 2.0 _imageEdgeInsets.bottom = (-textSize.height - imageToTitleSpacing) / 2.0 _titleEdgeInsets.top = (-imageSize.height - imageToTitleSpacing) / 2.0 _titleEdgeInsets.bottom = (imageSize.height + imageToTitleSpacing) / 2.0 _contentEdgeInsets.top = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0 _contentEdgeInsets.bottom = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0 //only works with contentVerticalAlignment = .center contentVerticalAlignment = .center case .top: _imageEdgeInsets.top = (-textSize.height - imageToTitleSpacing) / 2.0 _imageEdgeInsets.bottom = (textSize.height + imageToTitleSpacing) / 2.0 _titleEdgeInsets.top = (imageSize.height + imageToTitleSpacing) / 2.0 _titleEdgeInsets.bottom = (-imageSize.height - imageToTitleSpacing) / 2.0 _contentEdgeInsets.top = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0 _contentEdgeInsets.bottom = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0 //only works with contentVerticalAlignment = .center contentVerticalAlignment = .center case .center: //only works with contentVerticalAlignment = .center contentVerticalAlignment = .center break case .unset: break } switch imageHorizontalAlignment { case .left: _imageEdgeInsets.left = -halfImageToTitleSpacing _imageEdgeInsets.right = halfImageToTitleSpacing _titleEdgeInsets.left = halfImageToTitleSpacing _titleEdgeInsets.right = -halfImageToTitleSpacing _contentEdgeInsets.left = halfImageToTitleSpacing _contentEdgeInsets.right = halfImageToTitleSpacing case .right: _imageEdgeInsets.left = textSize.width + halfImageToTitleSpacing _imageEdgeInsets.right = -textSize.width - halfImageToTitleSpacing _titleEdgeInsets.left = -imageSize.width - halfImageToTitleSpacing _titleEdgeInsets.right = imageSize.width + halfImageToTitleSpacing _contentEdgeInsets.left = halfImageToTitleSpacing _contentEdgeInsets.right = halfImageToTitleSpacing case .center: _imageEdgeInsets.left = textSize.width / 2.0 _imageEdgeInsets.right = -textSize.width / 2.0 _titleEdgeInsets.left = -imageSize.width / 2.0 _titleEdgeInsets.right = imageSize.width / 2.0 _contentEdgeInsets.left = -((imageSize.width + textSize.width) - max (imageSize.width, textSize.width)) / 2.0 _contentEdgeInsets.right = -((imageSize.width + textSize.width) - max (imageSize.width, textSize.width)) / 2.0 case .unset: break } _contentEdgeInsets.top += extraContentEdgeInsets.top _contentEdgeInsets.bottom += extraContentEdgeInsets.bottom _contentEdgeInsets.left += extraContentEdgeInsets.left _contentEdgeInsets.right += extraContentEdgeInsets.right _imageEdgeInsets.top += extraImageEdgeInsets.top _imageEdgeInsets.bottom += extraImageEdgeInsets.bottom _imageEdgeInsets.left += extraImageEdgeInsets.left _imageEdgeInsets.right += extraImageEdgeInsets.right _titleEdgeInsets.top += extraTitleEdgeInsets.top _titleEdgeInsets.bottom += extraTitleEdgeInsets.bottom _titleEdgeInsets.left += extraTitleEdgeInsets.left _titleEdgeInsets.right += extraTitleEdgeInsets.right super.imageEdgeInsets = _imageEdgeInsets super.titleEdgeInsets = _titleEdgeInsets super.contentEdgeInsets = _contentEdgeInsets } else { super.imageEdgeInsets = extraImageEdgeInsets super.titleEdgeInsets = extraTitleEdgeInsets super.contentEdgeInsets = extraContentEdgeInsets } super.layoutSubviews() } }


También si quieres hacer algo parecido a

Necesitas

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

  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 actualizar esto en cada salida de relé

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) } } } }


Una forma elegante en Swift 3 y mejor entender:

override func imageRect(forContentRect contentRect: CGRect) -> CGRect { let leftMargin:CGFloat = 40 let imgWidth:CGFloat = 24 let imgHeight:CGFloat = 24 return CGRect(x: leftMargin, y: (contentRect.size.height-imgHeight) * 0.5, width: imgWidth, height: imgHeight) } override func titleRect(forContentRect contentRect: CGRect) -> CGRect { let leftMargin:CGFloat = 80 let rightMargin:CGFloat = 80 return CGRect(x: leftMargin, y: 0, width: contentRect.size.width-leftMargin-rightMargin, height: contentRect.size.height) } override func backgroundRect(forBounds bounds: CGRect) -> CGRect { let leftMargin:CGFloat = 10 let rightMargin:CGFloat = 10 let topMargin:CGFloat = 10 let bottomMargin:CGFloat = 10 return CGRect(x: leftMargin, y: topMargin, width: bounds.size.width-leftMargin-rightMargin, height: bounds.size.height-topMargin-bottomMargin) } override func contentRect(forBounds bounds: CGRect) -> CGRect { let leftMargin:CGFloat = 5 let rightMargin:CGFloat = 5 let topMargin:CGFloat = 5 let bottomMargin:CGFloat = 5 return CGRect(x: leftMargin, y: topMargin, width: bounds.size.width-leftMargin-rightMargin, height: bounds.size.height-topMargin-bottomMargin) }


Una pequeña adición a la respuesta de Riley Avron a los cambios en la configuración regional de la cuenta:

extension UIButton { func centerTextAndImage(spacing: CGFloat) { let insetAmount = spacing / 2 let writingDirection = UIApplication.sharedApplication().userInterfaceLayoutDirection let factor: CGFloat = writingDirection == .LeftToRight ? 1 : -1 self.imageEdgeInsets = UIEdgeInsets(top: 0, left: -insetAmount*factor, bottom: 0, right: insetAmount*factor) self.titleEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount*factor, bottom: 0, right: -insetAmount*factor) self.contentEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: insetAmount) } }


Yo escribo código bewlow. Funciona bien en la versión del producto. Supprot Swift 4.2 +

extension UIButton{ enum ImageTitleRelativeLocation { case imageUpTitleDown case imageDownTitleUp case imageLeftTitleRight case imageRightTitleLeft } func centerContentRelativeLocation(_ relativeLocation: ImageTitleRelativeLocation, spacing: CGFloat = 0) { assert(contentVerticalAlignment == .center, "only works with contentVerticalAlignment = .center !!!") guard (title(for: .normal) != nil) || (attributedTitle(for: .normal) != nil) else { assert(false, "TITLE IS NIL! SET TITTLE FIRST!") return } guard let imageSize = self.currentImage?.size else { assert(false, "IMGAGE IS NIL! SET IMAGE FIRST!!!") return } guard let titleSize = titleLabel? .systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) else { assert(false, "TITLELABEL IS NIL!") return } let horizontalResistent: CGFloat // extend contenArea in case of title is shrink if frame.width < titleSize.width + imageSize.width { horizontalResistent = titleSize.width + imageSize.width - frame.width print("horizontalResistent", horizontalResistent) } else { horizontalResistent = 0 } var adjustImageEdgeInsets: UIEdgeInsets = .zero var adjustTitleEdgeInsets: UIEdgeInsets = .zero var adjustContentEdgeInsets: UIEdgeInsets = .zero let verticalImageAbsOffset = abs((titleSize.height + spacing) / 2) let verticalTitleAbsOffset = abs((imageSize.height + spacing) / 2) switch relativeLocation { case .imageUpTitleDown: adjustImageEdgeInsets.top = -verticalImageAbsOffset adjustImageEdgeInsets.bottom = verticalImageAbsOffset adjustImageEdgeInsets.left = titleSize.width / 2 + horizontalResistent / 2 adjustImageEdgeInsets.right = -titleSize.width / 2 - horizontalResistent / 2 adjustTitleEdgeInsets.top = verticalTitleAbsOffset adjustTitleEdgeInsets.bottom = -verticalTitleAbsOffset adjustTitleEdgeInsets.left = -imageSize.width / 2 + horizontalResistent / 2 adjustTitleEdgeInsets.right = imageSize.width / 2 - horizontalResistent / 2 adjustContentEdgeInsets.top = spacing adjustContentEdgeInsets.bottom = spacing adjustContentEdgeInsets.left = -horizontalResistent adjustContentEdgeInsets.right = -horizontalResistent case .imageDownTitleUp: adjustImageEdgeInsets.top = verticalImageAbsOffset adjustImageEdgeInsets.bottom = -verticalImageAbsOffset adjustImageEdgeInsets.left = titleSize.width / 2 + horizontalResistent / 2 adjustImageEdgeInsets.right = -titleSize.width / 2 - horizontalResistent / 2 adjustTitleEdgeInsets.top = -verticalTitleAbsOffset adjustTitleEdgeInsets.bottom = verticalTitleAbsOffset adjustTitleEdgeInsets.left = -imageSize.width / 2 + horizontalResistent / 2 adjustTitleEdgeInsets.right = imageSize.width / 2 - horizontalResistent / 2 adjustContentEdgeInsets.top = spacing adjustContentEdgeInsets.bottom = spacing adjustContentEdgeInsets.left = -horizontalResistent adjustContentEdgeInsets.right = -horizontalResistent case .imageLeftTitleRight: adjustImageEdgeInsets.left = -spacing / 2 adjustImageEdgeInsets.right = spacing / 2 adjustTitleEdgeInsets.left = spacing / 2 adjustTitleEdgeInsets.right = -spacing / 2 adjustContentEdgeInsets.left = spacing adjustContentEdgeInsets.right = spacing case .imageRightTitleLeft: adjustImageEdgeInsets.left = titleSize.width + spacing / 2 adjustImageEdgeInsets.right = -titleSize.width - spacing / 2 adjustTitleEdgeInsets.left = -imageSize.width - spacing / 2 adjustTitleEdgeInsets.right = imageSize.width + spacing / 2 adjustContentEdgeInsets.left = spacing adjustContentEdgeInsets.right = spacing } imageEdgeInsets = adjustImageEdgeInsets titleEdgeInsets = adjustTitleEdgeInsets contentEdgeInsets = adjustContentEdgeInsets setNeedsLayout() } }


Swift 4.x

extension UIButton { func centerTextAndImage(spacing: CGFloat) { let insetAmount = spacing / 2 let writingDirection = UIApplication.shared.userInterfaceLayoutDirection let factor: CGFloat = writingDirection == .leftToRight ? 1 : -1 self.imageEdgeInsets = UIEdgeInsets(top: 0, left: -insetAmount*factor, bottom: 0, right: insetAmount*factor) self.titleEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount*factor, bottom: 0, right: -insetAmount*factor) self.contentEdgeInsets = UIEdgeInsets(top: 0, left: insetAmount, bottom: 0, right: insetAmount) } }

Uso :

button.centerTextAndImage(spacing: 10.0)