under right and iphone image text uibutton label

iphone - right - Etiqueta debajo de imagen en UIButton



uibutton right image (26)

@Tiago cambio tu respuesta de esta manera. Funciona bien con todos los tamaños

func alignImageAndTitleVertically(padding: CGFloat = 5.0) { self.sizeToFit() let imageSize = self.imageView!.frame.size let titleSize = self.titleLabel!.frame.size let totalHeight = imageSize.height + titleSize.height + padding self.imageEdgeInsets = UIEdgeInsets( top: -(totalHeight - imageSize.height), left: 0, bottom: 0, right: -titleSize.width ) self.titleEdgeInsets = UIEdgeInsets( top: 0, left: 0, bottom: -(totalHeight - titleSize.height), right: titleSize.height ) }

Intento crear un botón que tenga algo de texto debajo del ícono (al igual que los botones de la aplicación), sin embargo, parece ser bastante difícil de lograr. ¿Alguna idea de cómo puedo conseguir que el texto se muestre debajo de la imagen con un UIButton?


Algo así dentro de la subclase UIButton

public override func layoutSubviews() { super.layoutSubviews() imageEdgeInsets = UIEdgeInsetsMake(-10, 0, 0, 0) titleEdgeInsets = UIEdgeInsetsMake(0, -bounds.size.width/2 - 10, -30, 0) }


Aquí está la respuesta de "Bear With Me" como una subclase en Swift 2.0 . Para usarlo simplemente cambie su clase de botón en Interface Builder a VerticalButton y mágicamente actualizará la vista previa.

También lo actualicé para calcular el tamaño de contenido intrínseco correcto para el diseño automático.

import UIKit @IBDesignable class VerticalButton: UIButton { @IBInspectable var padding: CGFloat = 8 override func prepareForInterfaceBuilder() { super.prepareForInterfaceBuilder() update() } override func layoutSubviews() { super.layoutSubviews() update() } func update() { let imageBounds = self.imageView!.bounds let titleBounds = self.titleLabel!.bounds let totalHeight = CGRectGetHeight(imageBounds) + padding + CGRectGetHeight(titleBounds) self.imageEdgeInsets = UIEdgeInsets( top: -(totalHeight - CGRectGetHeight(imageBounds)), left: 0, bottom: 0, right: -CGRectGetWidth(titleBounds) ) self.titleEdgeInsets = UIEdgeInsets( top: 0, left: -CGRectGetWidth(imageBounds), bottom: -(totalHeight - CGRectGetHeight(titleBounds)), right: 0 ) } override func intrinsicContentSize() -> CGSize { let imageBounds = self.imageView!.bounds let titleBounds = self.titleLabel!.bounds let width = CGRectGetWidth(imageBounds) > CGRectGetWidth(titleBounds) ? CGRectGetWidth(imageBounds) : CGRectGetWidth(titleBounds) let height = CGRectGetHeight(imageBounds) + padding + CGRectGetHeight(titleBounds) return CGSizeMake(width, height) } }


Aquí está mi subclase de UIButton que resuelve este problema:

@implementation MyVerticalButton @synthesize titleAtBottom; // BOOL property - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self.titleAtBottom = YES; } return self; } - (CGSize)sizeThatFits:(CGSize)size { self.titleLabel.text = [self titleForState: self.state]; UIEdgeInsets imageInsets = self.imageEdgeInsets; UIEdgeInsets titleInsets = self.titleEdgeInsets; CGSize imageSize = [self imageForState: self.state].size; if (!CGSizeEqualToSize(imageSize, CGSizeZero)) { imageSize.width += imageInsets.left + imageInsets.right; imageSize.height += imageInsets.top + imageInsets.bottom; } CGSize textSize = [self.titleLabel sizeThatFits: CGSizeMake(size.width - titleInsets.left - titleInsets.right, size.height -(imageSize.width + titleInsets.top+titleInsets.bottom))]; if (!CGSizeEqualToSize(textSize, CGSizeZero)) { textSize.width += titleInsets.left + titleInsets.right; textSize.height += titleInsets.top + titleInsets.bottom; } CGSize result = CGSizeMake(MAX(textSize.width, imageSize.width), textSize.height + imageSize.height); return result; } - (void)layoutSubviews { // needed to update all properities of child views: [super layoutSubviews]; CGRect bounds = self.bounds; CGRect titleFrame = UIEdgeInsetsInsetRect(bounds, self.titleEdgeInsets); CGRect imageFrame = UIEdgeInsetsInsetRect(bounds, self.imageEdgeInsets); if (self.titleAtBottom) { CGFloat titleHeight = [self.titleLabel sizeThatFits: titleFrame.size].height; titleFrame.origin.y = CGRectGetMaxY(titleFrame)-titleHeight; titleFrame.size.height = titleHeight; titleFrame = CGRectStandardize(titleFrame); self.titleLabel.frame = titleFrame; CGFloat imageBottom = CGRectGetMinY(titleFrame)-(self.titleEdgeInsets.top+self.imageEdgeInsets.bottom); imageFrame.size.height = imageBottom - CGRectGetMinY(imageFrame); self.imageView.frame = CGRectStandardize(imageFrame); } else { CGFloat titleHeight = [self.titleLabel sizeThatFits: titleFrame.size].height; titleFrame.size.height = titleHeight; titleFrame = CGRectStandardize(titleFrame); self.titleLabel.frame = titleFrame; CGFloat imageTop = CGRectGetMaxY(titleFrame)+(self.titleEdgeInsets.bottom+self.imageEdgeInsets.top); imageFrame.size.height = CGRectGetMaxY(imageFrame) - imageTop; self.imageView.frame = CGRectStandardize(imageFrame); } } - (void)setTitleAtBottom:(BOOL)newTitleAtBottom { if (titleAtBottom!=newTitleAtBottom) { titleAtBottom=newTitleAtBottom; [self setNeedsLayout]; } } @end

Eso es. Funciona como el encanto. El problema puede aparecer si el botón será demasiado pequeño para ajustarse al título y al texto.


Creo que una de las mejores maneras de hacerlo es subclasificando UIButton y anulando algunos métodos de renderizado:

- (void)awakeFromNib { [super awakeFromNib]; [self setupSubViews]; } - (instancetype)init { if (self = [super init]) { [self setupSubViews]; } return self; } - (void)setupSubViews { [self.imageView setTranslatesAutoresizingMaskIntoConstraints:NO]; [self addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.imageView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]]; [self.titleLabel setTranslatesAutoresizingMaskIntoConstraints:NO]; [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[imageView][titleLabel]|" options:NSLayoutFormatAlignAllCenterX metrics:nil views:@{@"imageView": self.imageView, @"titleLabel": self.titleLabel}]]; } - (CGSize)intrinsicContentSize { CGSize imageSize = self.imageView.image.size; CGSize titleSize = [self.titleLabel.text sizeWithAttributes:@{NSFontAttributeName: self.titleLabel.font}]; return CGSizeMake(MAX(imageSize.width, titleSize.width), imageSize.height + titleSize.height); }


Descubrí que la respuesta de Simeon era probablemente la mejor, pero me estaba dando resultados extraños en algunos botones y no entendía por qué. Entonces, usando su respuesta como base, implementé mis botones como se muestra a continuación:

#define PADDING 2.0f @implementation OOButtonVerticalImageText -(CGSize) intrinsicContentSize { CGSize size = [super intrinsicContentSize]; CGFloat labelHeight = 0.0f; CGSize titleSize = [self.titleLabel sizeThatFits:CGSizeMake([self contentRectForBounds:self.bounds].size.width, CGFLOAT_MAX)]; labelHeight = titleSize.height; return CGSizeMake(MAX(titleSize.width, self.imageView.image.size.width), self.imageView.image.size.height + labelHeight + PADDING); } -(void) layoutSubviews { [super layoutSubviews]; CGSize titleSize = [self.titleLabel sizeThatFits:CGSizeMake([self contentRectForBounds:self.bounds].size.width, CGFLOAT_MAX)]; self.titleLabel.frame = CGRectMake((self.bounds.size.width - titleSize.width)/2.0f, self.bounds.size.height - titleSize.height - PADDING, titleSize.width, titleSize.height); CGSize ivSize = self.imageView.frame.size; self.imageView.frame = CGRectMake((self.bounds.size.width - ivSize.width)/2.0f, self.titleLabel.frame.origin.y - ivSize.height - PADDING, ivSize.width, ivSize.height); } @end


En Xcode, puede simplemente configurar el recuadro izquierdo del título del borde a negativo del ancho de la imagen. Esto mostrará la etiqueta en el centro de la imagen.

Para que la etiqueta se muestre debajo de la imagen (al igual que los botones de la aplicación), es posible que necesite establecer el recuadro superior del título del borde en algún número positivo.


Es bastante simple.

En lugar de esto:

button.setImage(UIImage(named: "image"), forState: .Normal)

Utilizar esta:

button.setBackgroundImage(UIImage(named: "image", forState: .Normal)

Luego puede agregar texto en el botón fácilmente usando:

// button.titleLabel! .font = UIFont (nombre: "FontName", tamaño: 30)

button.setTitle("TitleText", forState: UIControlState.Normal)


Esta es la gran respuesta de "Bear With Me" en Swift.

extension UIButton { func alignImageAndTitleVertically(padding: CGFloat = 6.0) { let imageSize = self.imageView!.frame.size let titleSize = self.titleLabel!.frame.size let totalHeight = imageSize.height + titleSize.height + padding self.imageEdgeInsets = UIEdgeInsets( top: -(totalHeight - imageSize.height), left: 0, bottom: 0, right: -titleSize.width ) self.titleEdgeInsets = UIEdgeInsets( top: 0, left: -imageSize.width, bottom: -(totalHeight - titleSize.height), right: 0 ) } }


Esta es una versión modificada de la excelente respuesta de Erik W. Pero en lugar de colocar la imagen centrada en la parte superior de la vista, coloca la imagen y la etiqueta centradas en la vista como un grupo.

La diferencia es:

+-----------+ | ( ) | | Hello | // Erik W''s code | | | | +-----------+

vs

+-----------+ | | | ( ) | // My modified version | Hello | | | +-----------+

Fuente a continuación:

-(void)layoutSubviews { [super layoutSubviews]; CGRect titleLabelFrame = self.titleLabel.frame; CGSize labelSize = [self.titleLabel.text sizeWithFont:self.titleLabel.font constrainedToSize:CGSizeMake(self.frame.size.width, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping]; CGRect imageFrame = self.imageView.frame; CGSize fitBoxSize = (CGSize){.height = labelSize.height + kTextTopPadding + imageFrame.size.height, .width = MAX(imageFrame.size.width, labelSize.width)}; CGRect fitBoxRect = CGRectInset(self.bounds, (self.bounds.size.width - fitBoxSize.width)/2, (self.bounds.size.height - fitBoxSize.height)/2); imageFrame.origin.y = fitBoxRect.origin.y; imageFrame.origin.x = CGRectGetMidX(fitBoxRect) - (imageFrame.size.width/2); self.imageView.frame = imageFrame; // Adjust the label size to fit the text, and move it below the image titleLabelFrame.size.width = labelSize.width; titleLabelFrame.size.height = labelSize.height; titleLabelFrame.origin.x = (self.frame.size.width / 2) - (labelSize.width / 2); titleLabelFrame.origin.y = fitBoxRect.origin.y + imageFrame.size.height + kTextTopPadding; self.titleLabel.frame = titleLabelFrame; }

FYI: Esto puede romperse cuando se combina con animaciones de UIView, ya que se llama a layoutSubviews durante ellas.


Este es un botón de título centrado simple implementado en Swift anulando titleRect(forContentRect:) e imageRect(forContentRect:) . También implementa intrinsicContentSize para su uso con AutoLayout.

import UIKit class CenteredButton: UIButton { override func titleRect(forContentRect contentRect: CGRect) -> CGRect { let rect = super.titleRect(forContentRect: contentRect) return CGRect(x: 0, y: contentRect.height - rect.height + 5, width: contentRect.width, height: rect.height) } override func imageRect(forContentRect contentRect: CGRect) -> CGRect { let rect = super.imageRect(forContentRect: contentRect) let titleRect = self.titleRect(forContentRect: contentRect) return CGRect(x: contentRect.width/2.0 - rect.width/2.0, y: (contentRect.height - titleRect.height)/2.0 - rect.height/2.0, width: rect.width, height: rect.height) } override var intrinsicContentSize: CGSize { let size = super.intrinsicContentSize if let image = imageView?.image { var labelHeight: CGFloat = 0.0 if let size = titleLabel?.sizeThatFits(CGSize(width: self.contentRect(forBounds: self.bounds).width, height: CGFloat.greatestFiniteMagnitude)) { labelHeight = size.height } return CGSize(width: size.width, height: image.size.height + labelHeight + 5) } return size } override init(frame: CGRect) { super.init(frame: frame) centerTitleLabel() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) centerTitleLabel() } private func centerTitleLabel() { self.titleLabel?.textAlignment = .center } }


Haga una imagen que tenga una imagen con texto debajo y use esa imagen para su botón.


La solución de Dave en Swift:

override func layoutSubviews() { super.layoutSubviews() if let imageView = self.imageView { imageView.frame.origin.x = (self.bounds.size.width - imageView.frame.size.width) / 2.0 imageView.frame.origin.y = 0.0 } if let titleLabel = self.titleLabel { titleLabel.frame.origin.x = (self.bounds.size.width - titleLabel.frame.size.width) / 2.0 titleLabel.frame.origin.y = self.bounds.size.height - titleLabel.frame.size.height } }


La solution @ simeon en Objective-C

#import "CenteredButton.h" @implementation CenteredButton - (CGRect)titleRectForContentRect:(CGRect)contentRect { CGRect rect = [super titleRectForContentRect: contentRect]; return CGRectMake(0, contentRect.size.height - rect.size.height - 5, contentRect.size.width, rect.size.height); } - (CGRect)imageRectForContentRect:(CGRect)contentRect { CGRect rect = [super imageRectForContentRect: contentRect]; CGRect titleRect = [self titleRectForContentRect: contentRect]; return CGRectMake(contentRect.size.width / 2.0 - rect.size.width / 2.0, (contentRect.size.height - titleRect.size.height)/2.0 - rect.size.height/2.0, rect.size.width, rect.size.height); } - (CGSize)intrinsicContentSize { CGSize imageSize = [super intrinsicContentSize]; if (self.imageView.image) { UIImage* image = self.imageView.image; CGFloat labelHeight = 0.0; CGSize labelSize = [self.titleLabel sizeThatFits: CGSizeMake([self contentRectForBounds: self.bounds].size.width, CGFLOAT_MAX)]; if (CGSizeEqualToSize(imageSize, labelSize)) { labelHeight = imageSize.height; } return CGSizeMake(MAX(labelSize.width, imageSize.width), image.size.height + labelHeight + 5); } return imageSize; } - (id) initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self centerTitleLabel]; } return self; } - (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { [self centerTitleLabel]; } return self; } - (void)centerTitleLabel { self.titleLabel.textAlignment = NSTextAlignmentCenter; } @end


O simplemente puede usar esta categoría:

ObjC

@interface UIButton (VerticalLayout) - (void)centerVerticallyWithPadding:(float)padding; - (void)centerVertically; @end @implementation UIButton (VerticalLayout) - (void)centerVerticallyWithPadding:(float)padding { CGSize imageSize = self.imageView.frame.size; CGSize titleSize = self.titleLabel.frame.size; CGFloat totalHeight = (imageSize.height + titleSize.height + padding); self.imageEdgeInsets = UIEdgeInsetsMake(- (totalHeight - imageSize.height), 0.0f, 0.0f, - titleSize.width); self.titleEdgeInsets = UIEdgeInsetsMake(0.0f, - imageSize.width, - (totalHeight - titleSize.height), 0.0f); self.contentEdgeInsets = UIEdgeInsetsMake(0.0f, 0.0f, titleSize.height, 0.0f); } - (void)centerVertically { const CGFloat kDefaultPadding = 6.0f; [self centerVerticallyWithPadding:kDefaultPadding]; } @end

Extensión Swift

extension UIButton { func centerVertically(padding: CGFloat = 6.0) { guard let imageViewSize = self.imageView?.frame.size, let titleLabelSize = self.titleLabel?.frame.size else { return } let totalHeight = imageViewSize.height + titleLabelSize.height + padding self.imageEdgeInsets = UIEdgeInsets( top: -(totalHeight - imageViewSize.height), left: 0.0, bottom: 0.0, right: -titleLabelSize.width ) self.titleEdgeInsets = UIEdgeInsets( top: 0.0, left: -imageViewSize.width, bottom: -(totalHeight - titleLabelSize.height), right: 0.0 ) self.contentEdgeInsets = UIEdgeInsets( top: 0.0, left: 0.0, bottom: titleLabelSize.height, right: 0.0 ) } }


Para controlar con precisión el tamaño y el diseño automático, puede probar esto: https://github.com/albert-zhang/AZCenterLabelButton ( Link )


Refactorizada la respuesta de icecrystal23.

Swift 3, funciona con autolayouts, xib, storyboards, puede ser animado.

El botón en la respuesta original de icecrystal23 tenía un marco mal calculado. Creo que lo arreglé

import UIKit class VerticallyButton: UIButton { var padding: CGFloat = 20.0 { didSet { setNeedsLayout() } } override var intrinsicContentSize: CGSize { let maxSize = CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude) if let titleSize = titleLabel?.sizeThatFits(maxSize), let imageSize = imageView?.sizeThatFits(maxSize) { let width = ceil(max(imageSize.width, titleSize.width)) let height = ceil(imageSize.height + titleSize.height + padding) return CGSize(width: width, height: height) } return super.intrinsicContentSize } override func layoutSubviews() { if let image = imageView?.image, let title = titleLabel?.attributedText { let imageSize = image.size let titleSize = title.size() titleEdgeInsets = UIEdgeInsetsMake(0.0, -imageSize.width, -(imageSize.height + padding), 0.0) imageEdgeInsets = UIEdgeInsetsMake(-(titleSize.height + padding), 0.0, 0.0, -titleSize.width) } super.layoutSubviews() } }


Se actualizó la respuesta de Kenny Winker desde que sizeWithFont quedó en desuso en iOS 7.

-(void)layoutSubviews { [super layoutSubviews]; int kTextTopPadding = 3; CGRect titleLabelFrame = self.titleLabel.frame; CGRect labelSize = [self.titleLabel.text boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGRectGetHeight(self.bounds)) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:self.titleLabel.font} context:nil]; CGRect imageFrame = self.imageView.frame; CGSize fitBoxSize = (CGSize){.height = labelSize.size.height + kTextTopPadding + imageFrame.size.height, .width = MAX(imageFrame.size.width, labelSize.size.width)}; CGRect fitBoxRect = CGRectInset(self.bounds, (self.bounds.size.width - fitBoxSize.width)/2, (self.bounds.size.height - fitBoxSize.height)/2); imageFrame.origin.y = fitBoxRect.origin.y; imageFrame.origin.x = CGRectGetMidX(fitBoxRect) - (imageFrame.size.width/2); self.imageView.frame = imageFrame; // Adjust the label size to fit the text, and move it below the image titleLabelFrame.size.width = labelSize.size.width; titleLabelFrame.size.height = labelSize.size.height; titleLabelFrame.origin.x = (self.frame.size.width / 2) - (labelSize.size.width / 2); titleLabelFrame.origin.y = fitBoxRect.origin.y + imageFrame.size.height + kTextTopPadding; self.titleLabel.frame = titleLabelFrame; }


Si subclase UIButton y override layoutSubviews , puede usar el siguiente para centrar la imagen y colocar el título centrado debajo de ella:

kTextTopPadding es una constante que tendrás que introducir que determina el espacio entre la imagen y el texto debajo de ella.

-(void)layoutSubviews { [super layoutSubviews]; // Move the image to the top and center it horizontally CGRect imageFrame = self.imageView.frame; imageFrame.origin.y = 0; imageFrame.origin.x = (self.frame.size.width / 2) - (imageFrame.size.width / 2); self.imageView.frame = imageFrame; // Adjust the label size to fit the text, and move it below the image CGRect titleLabelFrame = self.titleLabel.frame; CGSize labelSize = [self.titleLabel.text sizeWithFont:self.titleLabel.font constrainedToSize:CGSizeMake(self.frame.size.width, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping]; titleLabelFrame.size.width = labelSize.width; titleLabelFrame.size.height = labelSize.height; titleLabelFrame.origin.x = (self.frame.size.width / 2) - (labelSize.width / 2); titleLabelFrame.origin.y = self.imageView.frame.origin.y + self.imageView.frame.size.height + kTextTopPadding; self.titleLabel.frame = titleLabelFrame; }


Solo tiene que ajustar las tres inserciones de borde en función del tamaño de su imagen y etiqueta de título:

button.contentEdgeInsets = UIEdgeInsetsMake(0, 0, titleLabelBounds.height + 4, 0) button.titleEdgeInsets = UIEdgeInsetsMake(image.size.height + 8, -image.size.width, 0, 0) button.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, -titleLabelBounds.width)

Puede obtener los límites de la etiqueta del título llamando a sizeToFit después de configurar su texto. El espaciado horizontal debería funcionar independientemente del tamaño del texto, la fuente y la imagen, pero no conozco una solución única para lograr que el espaciado vertical y el borde inferior del contenido sean consistentes.


Subclase UIButton . Sobrescribir - layoutSubviews para mover las subviews incorporadas a nuevas posiciones:

- (void)layoutSubviews { [super layoutSubviews]; CGRect frame = self.imageView.frame; frame = CGRectMake(truncf((self.bounds.size.width - frame.size.width) / 2), 0.0f, frame.size.width, frame.size.height); self.imageView.frame = frame; frame = self.titleLabel.frame; frame = CGRectMake(truncf((self.bounds.size.width - frame.size.width) / 2), self.bounds.size.height - frame.size.height, frame.size.width, frame.size.height); self.titleLabel.frame = frame; }


Tomé una combinación de las respuestas aquí y se me ocurrió una que parece estar funcionando para mí, en Swift. No amo cómo sobreescribo las inserciones, pero funciona. Estaría abierto a sugerencias de mejoras en los comentarios. Parece que funciona correctamente con sizeToFit() y con diseño automático.

import UIKit /// A button that displays an image centered above the title. This implementation /// only works when both an image and title are set, and ignores /// any changes you make to edge insets. class CenteredButton: UIButton { let padding: CGFloat = 0.0 override func layoutSubviews() { if imageView?.image != nil && titleLabel?.text != nil { let imageSize: CGSize = imageView!.image!.size titleEdgeInsets = UIEdgeInsetsMake(0.0, -imageSize.width, -(imageSize.height + padding), 0.0) let labelString = NSString(string: titleLabel!.text!) let titleSize = labelString.sizeWithAttributes([NSFontAttributeName: titleLabel!.font]) imageEdgeInsets = UIEdgeInsetsMake(-(titleSize.height + padding), 0.0, 0.0, -titleSize.width) let edgeOffset = abs(titleSize.height - imageSize.height) / 2.0; contentEdgeInsets = UIEdgeInsetsMake(edgeOffset, 0.0, edgeOffset, 0.0) } super.layoutSubviews() } override func sizeThatFits(size: CGSize) -> CGSize { let defaultSize = super.sizeThatFits(size) if let titleSize = titleLabel?.sizeThatFits(size), let imageSize = imageView?.sizeThatFits(size) { return CGSize(width: ceil(max(imageSize.width, titleSize.width)), height: ceil(imageSize.height + titleSize.height + padding)) } return defaultSize } override func intrinsicContentSize() -> CGSize { let size = sizeThatFits(CGSize(width: CGFloat.max, height: CGFloat.max)) return size } }


Usé el método de los bordes insertados propuesto por Chris, pero como el ancho del botón era más pequeño que el ancho total de la imagen y el título del botón, el título se mostró como 3 puntos (...).

No pude aumentar el ancho del botón debido a razones de diseño.

Lo resolví cambiando el atributo Line Break a: "Clip". Eso hace que el título baje debajo de la imagen. Luego corregí su ubicación usando las inserciones. Esto funciona solo cuando existe el problema anterior.


Usando el código de Kenny Winker''s y simeon, creo este código rápido que funciona para mí.

import UIKit @IBDesignable class TopIconButton: UIButton { override func layoutSubviews() { super.layoutSubviews() let kTextTopPadding:CGFloat = 3.0; var titleLabelFrame = self.titleLabel!.frame; let labelSize = titleLabel!.sizeThatFits(CGSizeMake(CGRectGetWidth(self.contentRectForBounds(self.bounds)), CGFloat.max)) var imageFrame = self.imageView!.frame; let fitBoxSize = CGSizeMake(max(imageFrame.size.width, labelSize.width), labelSize.height + kTextTopPadding + imageFrame.size. height) let fitBoxRect = CGRectInset(self.bounds, (self.bounds.size.width - fitBoxSize.width)/2, (self.bounds.size.height - fitBoxSize. height)/2); imageFrame.origin.y = fitBoxRect.origin.y; imageFrame.origin.x = CGRectGetMidX(fitBoxRect) - (imageFrame.size.width/2); self.imageView!.frame = imageFrame; // Adjust the label size to fit the text, and move it below the image titleLabelFrame.size.width = labelSize.width; titleLabelFrame.size.height = labelSize.height; titleLabelFrame.origin.x = (self.frame.size.width / 2) - (labelSize.width / 2); titleLabelFrame.origin.y = fitBoxRect.origin.y + imageFrame.size.height + kTextTopPadding; self.titleLabel!.frame = titleLabelFrame; self.titleLabel!.textAlignment = .Center } }


corrigió una de las respuestas aquí:

Swift 3:

class CenteredButton: UIButton { override func titleRect(forContentRect contentRect: CGRect) -> CGRect { let rect = super.titleRect(forContentRect: contentRect) let imageRect = super.imageRect(forContentRect: contentRect) return CGRect(x: 0, y: imageRect.maxY + 10, width: contentRect.width, height: rect.height) } override func imageRect(forContentRect contentRect: CGRect) -> CGRect { let rect = super.imageRect(forContentRect: contentRect) let titleRect = self.titleRect(forContentRect: contentRect) return CGRect(x: contentRect.width/2.0 - rect.width/2.0, y: (contentRect.height - titleRect.height)/2.0 - rect.height/2.0, width: rect.width, height: rect.height) } override init(frame: CGRect) { super.init(frame: frame) centerTitleLabel() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) centerTitleLabel() } private func centerTitleLabel() { self.titleLabel?.textAlignment = .center } }


iOS 11 - Objetivo-C

-(void)layoutSubviews { [super layoutSubviews]; CGRect titleLabelFrame = self.titleLabel.frame; CGSize labelSize = [self.titleLabel.text sizeWithAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:12.0f]}]; CGSize adjustedLabelSize = CGSizeMake(ceilf(labelSize.width), ceilf(labelSize.height)); CGRect imageFrame = self.imageView.frame; CGSize fitBoxSize = (CGSize){.height = adjustedLabelSize.height + kTextTopPadding + imageFrame.size.height, .width = MAX(imageFrame.size.width, adjustedLabelSize.width)}; CGRect fitBoxRect = CGRectInset(self.bounds, (self.bounds.size.width - fitBoxSize.width)/2, (self.bounds.size.height - fitBoxSize.height)/2); imageFrame.origin.y = fitBoxRect.origin.y; imageFrame.origin.x = CGRectGetMidX(fitBoxRect) - (imageFrame.size.width/2); self.imageView.frame = imageFrame; // Adjust the label size to fit the text, and move it below the image titleLabelFrame.size.width = adjustedLabelSize.width; titleLabelFrame.size.height = adjustedLabelSize.height; titleLabelFrame.origin.x = (self.frame.size.width / 2) - (adjustedLabelSize.width / 2); titleLabelFrame.origin.y = fitBoxRect.origin.y + imageFrame.size.height + kTextTopPadding; self.titleLabel.frame = titleLabelFrame; }