ios uibutton uilabel autolayout

ios - UIButton que cambia de tamaño para ajustarse a su títuloLabel



uilabel autolayout (11)

Anule el - (CGSize) intrinsicContentSize en Custom UIButton como se indica a continuación.

C objetivo:

-(CGSize)intrinsicContentSize { CGSize titleLabelIntrinsicSize = [self.titleLabel intrinsicContentSize]; return CGSizeMake(titleLabelIntrinsicSize.width + self.contentEdgeInsets.left + self.contentEdgeInsets.right, titleLabelIntrinsicSize.height + self.contentEdgeInsets.top + self.contentEdgeInsets.bottom); }

Swfit:

override var intrinsicContentSize: CGSize { get { if let thisSize = self.titleLabel?.intrinsicContentSize { return CGSize(width: thisSize.width + self.contentEdgeInsets.left + self.contentEdgeInsets.right, height: thisSize.height + self.contentEdgeInsets.top + self.contentEdgeInsets.bottom) } return super.intrinsicContentSize } }

Tengo un UIButton que agrego a la vista de mi controlador de vista en un guión gráfico. Agrego restricciones de centrado para posicionarlo y restricciones de espacio iniciales para limitar su ancho. En el código agrego:

self.button.titleLabel.numberOfLines = 0; self.button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping; [self.button setTitle:@"A real real real real real real real real long long name." forState:UIControlStateNormal]; self.button.backgroundColor = [UIColor redColor]; self.button.titleLabel.backgroundColor = [UIColor blueColor];

El resultado se muestra a continuación:

Quiero que el botón se ajuste a su contenido. ¿Cómo puedo hacer esto?

He intentado

[self.button sizeToFit];

y he intentado establecer las restricciones de autolayout de la resistencia de compresión y la compresión de contenido según las prioridades requeridas.

También he intentado establecer explícitamente el contentEdgeInsets y titleEdgeInsets en UIEdgeInsetsZero y llamar a invalidateIntrinsicContentSize .

También he notado que si coloco caracteres de nueva línea en la cadena de título, el botón parece cambiar de tamaño para ajustarse a su contenido.

Me estoy ejecutando en Xcode 6 y iOS 8 en el iPhone 6 Simulator.


Conseguí que esto funcionara, pero tienes que usar un botón personalizado, no un tipo de sistema. Dé al botón tanto restricciones de ancho como de altura y haga un IBOutlet a la restricción de altura (heightCon en mi código) para que pueda ajustarlo en el código.

- (void)viewDidLoad { [super viewDidLoad]; self.button.titleLabel.numberOfLines = 0; self.button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping; [self.button setTitle:@"A real real real real real real real real long long name." forState:UIControlStateNormal]; [self.button addTarget:self action:@selector(doStuff:) forControlEvents:UIControlEventTouchUpInside]; self.button.backgroundColor = [UIColor redColor]; self.button.titleLabel.backgroundColor = [UIColor blueColor]; [self.button layoutIfNeeded]; // need this to update the button''s titleLabel''s size self.heightCon.constant = self.button.titleLabel.frame.size.height; }

Después de editar:

Descubrí que también puedes hacer esto de manera más simple, y con un botón del sistema si haces una subclase, y usas este código,

@implementation RDButton -(CGSize)intrinsicContentSize { return CGSizeMake(self.frame.size.width, self.titleLabel.frame.size.height); }

El método intrinsicContentSize anulado se llama cuando establece el título. No debe establecer una restricción de altura en este caso.


Estoy lejos de mi computadora, así que no puedo agregar el código en este momento, pero he encontrado una solución para esto antes.

Lo que puede hacer es crear un UILabel y agregar un UITapGestureRecognizer a la etiqueta. Haz lo que quieras por la acción del botón manejando el evento tap. Y también asegúrese de habilitar las interacciones del usuario en UILabel .

Esta etiqueta ahora se comportará como un botón de cambio de tamaño automático.


Lo que sugeriría es calcular el ancho del texto y calcular el marco usted mismo. No es complicado de todos modos, primero obtenga el ancho del texto:

[NSString sizeWithFont:font];

Realice una operación de modificación y encontrará fácilmente el número de líneas para el texto.

Tenga en cuenta que este método es para iOS7 anterior, para iOS 7 y después de que quiera probar

[NSString sizeWithAttributes:aDictionary];


Luché con esto por un tiempo y terminé haciéndolo subclasificar a UIButton y agregando estas dos funciones

class GoalsButton: UIButton { override var intrinsicContentSize: CGSize { return self.titleLabel!.intrinsicContentSize } // Whever the button is changed or needs to layout subviews, override func layoutSubviews() { super.layoutSubviews() titleLabel?.preferredMaxLayoutWidth = self.titleLabel!.frame.size.width } }


Tiene el mismo problema. Sucede solo si la UIButton de UIButton de titleLabel tiene más de una línea. ¿Es un error en UIKit?

Mi solución Swift:

class ResizableButton: UIButton { override var intrinsicContentSize: CGSize { let labelSize = titleLabel?.sizeThatFits(CGSize(width: frame.size.width, height: CGFloat.greatestFiniteMagnitude)) ?? .zero let desiredButtonSize = CGSize(width: labelSize.width + titleEdgeInsets.left + titleEdgeInsets.right, height: labelSize.height + titleEdgeInsets.top + titleEdgeInsets.bottom) return desiredButtonSize } }


Tuve el mismo problema con UIButton con texto de UIButton y también tenía una imagen. Utilicé sizeThatFits: para calcular el tamaño pero calculó la altura incorrecta.

No lo hice UIButtonTypeCustom , en lugar de eso lo llamé sizeThatFits: en la titleLabel del titleLabel del botón con un tamaño más pequeño (debido a la imagen en el botón):

CGSize buttonSize = [button sizeThatFits:CGSizeMake(maxWidth, maxHeight)]; CGSize labelSize = [button.titleLabel sizeThatFits:CGSizeMake(maxWidth - offset, maxHeight)]; // offset for image buttonSize.height = labelSize.height; buttonFrame.size = buttonSize;

Y luego utilicé la altura de ese tamaño para ajustar el marco del botón correctamente, y FUNCIONÓ :)

Tal vez tengan algún error en el tamaño interno de UIButton .


Tuve que invalidar el tamaño del contenido intrínseco cuando se diseñaron las vistas y luego calcular la altura del botón para la propiedad intrinsicContentSize.

Aquí está el código en Swift3 / Xcode 9

override func layoutSubviews() { self.invalidateIntrinsicContentSize() super.layoutSubviews() } override var intrinsicContentSize: CGSize { return CGSize(width: self.frame.size.width, height: titleLabel!.frame.size.height + contentEdgeInsets.top + contentEdgeInsets.bottom) }


[self.button sizeToFit] debería funcionar si su Autolayout está desactivado. Si tiene que usar autolayout, otras sugerencias (calculando el ancho de línea), etc. son más apropiadas.


Swift versión 4.x de Kubba''s respuesta de Kubba''s :

Debe actualizar el Salto de línea como Clip / WordWrap / en el generador de Interfaz para los botones correspondientes.

class ResizableButton: UIButton { override var intrinsicContentSize: CGSize { let labelSize = titleLabel?.sizeThatFits(CGSize(width: frame.width, height: .greatestFiniteMagnitude)) ?? .zero let desiredButtonSize = CGSize(width: labelSize.width + titleEdgeInsets.left + titleEdgeInsets.right, height: labelSize.height + titleEdgeInsets.top + titleEdgeInsets.bottom) return desiredButtonSize } }


class SFResizableButton: UIButton { override var intrinsicContentSize: CGSize { get { var labelSize = CGSize.zero if let text = titleLabel?.text, let font = titleLabel?.font { labelSize.width = text.width(constrained: .greatestFiniteMagnitude, font: font) } else if let att = titleLabel?.attributedText { labelSize.width = att.width(constrained: .greatestFiniteMagnitude) } if let imageView = imageView { labelSize.width = labelSize.width + imageView.frame.width } let desiredButtonSize = CGSize(width: ceil(labelSize.width) + titleEdgeInsets.left + titleEdgeInsets.right + imageEdgeInsets.left + imageEdgeInsets.right, height: labelSize.height + titleEdgeInsets.top + titleEdgeInsets.bottom + imageEdgeInsets.top + imageEdgeInsets.bottom) return desiredButtonSize } } } extesion String { func width(constrained height: CGFloat, font: UIFont) -> CGFloat { let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height) let boundingBox = (self as NSString).boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil) return boundingBox.width } } extension NSAttributedString { func width(constrained height: CGFloat) -> CGFloat { let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height) let boundingBox = boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, context: nil) return boundingBox.width } }