UIButton que cambia el tamaño para ajustarse a su etiqueta de título
Tengo un UIButton
que agrego a la vista de mi controlador de vista en un guion gráfico. Agrego restricciones de centrado para posicionarlo y restricciones de espacio principales 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 el contenido abrazos y la resistencia a la compresión autolayout restricciones prioridades a requerido.
He también intentó establecer explícitamente contentEdgeInsets
y titleEdgeInsets
a UIEdgeInsetsZero
y llamar a invalidateIntrinsicContentSize
.
También he notado que si pongo caracteres de nueva línea en la cadena de título, el botón parece cambiar de tamaño para adaptarse a su contenido.
Me estoy ejecutando en Xcode 6 y iOS 8 en el simulador de iPhone 6.
11 answers
He conseguido que esto funcione, pero tienes que usar un botón personalizado, no un tipo de sistema. Dale al botón restricciones de anchura y altura, y haz un IBOutlet a la restricción de altura (heightCon en mi código) para que puedas ajustarla en 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:
Encontré 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 sobrescrito se llama cuando se establece el titular. No debe establecer una restricción de altura en este caso.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-03 05:05:13
Swift 4.x versión de respuesta de Kubba :
Necesita actualizar Salto de líneacomo Clip/WordWrap/ en el creador de interfaces a 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
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-21 07:56:37
Tengo el mismo problema. Solo sucede si UIButton
's titleLabel
tiene más de una línea. Es un error en UIKit?
Mi solución rápida:
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
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-05 06:53:04
Luché con esto durante un tiempo y terminé haciéndolo funcionar mediante la subclase UIButton y la adición de 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
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-10 15:57:54
Estoy lejos de mi computadora, así que no puedo agregar el código en este momento, pero he encontrado una solución a esto antes.
Lo que puede hacer es crear un UILabel
y agregar un UITapGestureRecognizer
a la etiqueta. Haz lo que quieras para 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 redimensionamiento automático.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-03 03:58:16
Lo que sugeriría es calcular el ancho del texto, y calcular el marco por ti mismo. No es complicado de todos modos, obtener el ancho del texto primero:
[NSString sizeWithFont:font];
Haga 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 pre, para iOS 7 y después es posible que desee probar
[NSString sizeWithAttributes:aDictionary];
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-03 04:22:16
[self.botón sizeToFit] debería funcionar si su diseño Automático está Desactivado. Si tiene que usar el diseño automático, entonces otras sugerencias (calcular el ancho de línea), etc., son más apropiadas.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-05 07:52:13
Yo tenía el mismo problema con UIButton
con multilined de texto, y también tenía una imagen. Usé sizeThatFits:
para calcular el tamaño, pero calculó la altura incorrecta.
No lo hice UIButtonTypeCustom
, en lugar de eso llamé sizeThatFits:
en el botón titleLabel
con un tamaño con un ancho 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 usé la altura de ese tamaño para establecer el marco del botón correctamente, y FUNCIONÓ:)
Tal vez tengan algún error en el tamaño interno de UIButton
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-01 08:20:40
Sobrescriba el -(CGSize)intrinsicContentSize en UIButton personalizado como se indica a continuación.
Objetivo-C:
-(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
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-31 07:39:09
Tuve que invalidar el tamaño de contenido intrínseco cuando se establecieron 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)
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-04 15:14:50
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
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-10 15:17:01