objective-c uilabel xcode4.5

objective c - ¿Cómo ajusto SizeToFit a UILabel cambiando solo la altura y no el ancho?



objective-c xcode4.5 (9)

[self.Review sizeToFit];

Resultado antes de sizeToFit:

NSStringFromCGRect(self.Review.frame): {{90, 20}, {198, 63}}

Resultado después de sizeToFit:

NSStringFromCGRect(self.Review.frame): {{90, 20}, {181, 45}}

Quiero que el ancho permanezca igual. Solo quiero cambiar la altura. El automask es

(lldb) po self.Review (UILabel *) $1 = 0x08bb0fe0 <UILabel: 0x8bb0fe0; frame = (90 20; 181 45); text = ''I''m at Mal Taman Anggrek ...''; clipsToBounds = YES; opaque = NO; autoresize = LM+RM+H; userInteractionEnabled = NO; layer = <CALayer: 0x8bb68b0>>

Sé que hay una manera de hacerlo con: ¿Cómo ajustar y hacer que el ancho de una UILabel se ajuste al tamaño del texto?

Las respuestas son extrañas (necesitamos reabastecer la información de la fuente). O no está claro

También necesitará definir un ancho máximo y decirle a su programa qué hacer si sizeToFit le da un ancho mayor que ese máximo.

sizeWithFont la extraña solución de usar sizeWithFont . Es extraño porque UILabel ya conoce la fuente en la etiqueta.

En realidad, ¿cómo se comporta sizeToFit de todos modos? ¿Cómo decide si necesitamos UILabel más delgado o más alto?


Respuesta para 2017 ...

c = CGSize (ancho: su Ancho, alto: CGFloat.greatestFiniteMagnitude)
resultado = tamañoThatFits (c) .height

Asi que...

let t = .... your UITextView let w = .... your known width of the item let trueHeight = t.sizeThatFits( CGSize(width: t, height: CGFloat.greatestFiniteMagnitude)).height

Eso es.

Muy a menudo, desea saber la diferencia de altura en comparación con una entrada de una sola línea "normal" .

Esto surge en particular si está creando algún tipo de celdas que no tienen nada que ver con UTableView (por ejemplo, algún tipo de vista de pila personalizada). Debe establecer la altura manualmente en algún punto. En su guión gráfico, contruya como desee, utilizando un texto de ejemplo de cualquier cadena corta (por ejemplo, "A") que, por supuesto, tendrá solo una línea en cualquier situación normal. Entonces haces algo como esto ...

func setTextWithSizeCorrection() { // an affaire iOS let t = .... your UITextView let w = .... your known width of the item let oneLineExample = "A" let actualText = yourDataSource[row].description.whatever // get the height as if with only one line... experimental.text = oneLineExample let oneLineHeight = t.sizeThatFits( CGSize(width: w, height: CGFloat.greatestFiniteMagnitude)).height // get the height with the actual long text... // (note that usually, you do not want a one-line minimum) experimental.text = (actualText == "") ? oneLineExample : actualText let neededHeight = t.sizeThatFits( CGSize(width: w, height: CGFloat.greatestFiniteMagnitude)).height experimental.text = actualText let delta = neededHeight - oneLineHeight set the height of your cell, or whatever it is(standardHeight + delta) }

Punto final: una de las cosas realmente estúpidas en iOS es que UITextView tiene una especie de margen extraño dentro de él. Esto significa que no puede simplemente intercambiar entre UITextViews y etiquetas; y causa muchos otros problemas. Apple no ha solucionado este problema desde el momento de la escritura. Solucionar el problema es difícil: el siguiente enfoque generalmente es correcto:

@IBDesignable class UITextViewFixed: UITextView { override func layoutSubviews() { super.layoutSubviews() setup() } func setup() { textContainerInset = UIEdgeInsets.zero; textContainer.lineFragmentPadding = 0; } }

El UITextView roto e inutilizable de Apple ...

UITextViewFixed que es, en la mayoría de los casos, una solución aceptable:

(Amarillo añadido para mayor claridad)


Así es como se hace. Debido a que la etiqueta ya contiene la información de la fuente, incluyéndola en este método, la llamada es trivial.

CGSize size = [label.text sizeWithFont:label.font constrainedToSize:CGSizeMake(maxWidth, MAXFLOAT) lineBreakMode:UILineBreakModeWordWrap]; CGRect labelFrame = label.frame; labelFrame.size.height = size.height; label.frame = labelFrame;

La versión Swift utiliza el límite más boundingRectWithSize :

let maxHeight = CGFloat.infinity let rect = label.attributedText?.boundingRectWithSize(CGSizeMake(maxWidth, maxHeight), options: .UsesLineFragmentOrigin, context: nil) var frame = label.frame frame.size.height = rect.size.height label.frame = frame


Creo que no debes usar los métodos de size... UILabel , UILabel ya tiene una API para eso, como señala @vatrif (que internamente probablemente usa solo los métodos de NSString ).

Sin embargo, creo que la API de UILabel podría mejorarse. Por eso creo que una categoría sería la solución más elegante:

// UILabel+Resize.h @interface UILabel (Resize) - (void)sizeToFitHeight; @end // UILabel+Resize.m @implementation UILabel (Resize) - (void)sizeToFitHeight { CGSize size = [self sizeThatFits:CGSizeMake(self.frame.size.width, CGFLOAT_MAX)]; CGRect frame = self.frame; frame.size.height = size.height; self.frame = frame; } @end

Solo una cosa: no estoy seguro del nombre apropiado para ese método:

  • sizeToFitHeight?
  • heightToFit?

Comentarios muy apreciados, gracias!


La API acordada se beneficiaría de esta adición. Haga su vida más fácil y agregue una extensión a la clase UILabel en Swift de la siguiente manera:

extension UILabel { func sizeToFitHeight() { let size:CGSize = self.sizeThatFits(CGSizeMake(self.frame.size.width, CGFloat.max)) var frame:CGRect = self.frame frame.size.height = size.height self.frame = frame } }


Puede obtener el mismo resultado con sizeThatFits.

CGSize size = [label sizeThatFits:CGSizeMake(label.frame.size.width, CGFLOAT_MAX)]; CGRect frame = label.frame; frame.size.height = size.height; label.frame = frame;

O, como alternativa, con sizeToFit.

CGRect frame = label.frame; [label sizeToFit]; frame.size.height = label.frame.size.height; label.frame = frame;


Swift 3 versión de la respuesta de Mundi :

let maxHeight: CGFloat = 10000 let rect = label.attributedText!.boundingRect(with: CGSize(width: maxWidth, height: maxHeight), options: .usesLineFragmentOrigin, context: nil) var frame = labe.frame frame.size.height = rect.size.height label.frame = frame


Una extensión fácil para este problema para Swift 3.

extension UILabel { func sizeToFitHeight() { let size: CGSize = self.sizeThatFits(CGSize.init(width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude)) var frame:CGRect = self.frame frame.size.height = size.height self.frame = frame } }


sizeToFit funciona de maravilla. El único problema es que se basa en el tamaño actual del control.

Por ejemplo, si está reciclando celdas de la vista de tabla con una etiqueta, la etiqueta puede haberse reducido en ancho en una celda anterior y, por lo tanto, la llamada a sizeToFit puede parecer poco confiable.

Simplemente restablezca el ancho original de su control antes de enviar el mensaje sizeToFit.


SOLUCIÓN FIJA PARA SWIFT 3

Use CGFloat.greatestFiniteMagnitude para maxHeight.

let size = CGSize.init(width: yourLabel.frame.size.width, height: CGFloat.greatestFiniteMagnitude) let rect = errorLabel.attributedText?.boundingRect(with: size, options: .usesLineFragmentOrigin, context: nil) var frame = errorLabel.frame frame.size.height = (rect?.size.height)! errorLabel.frame = frame


O UIlabel extensión UIlabel y llama al método yourLabel. sizeToFitHeight() yourLabel. sizeToFitHeight()

extension UILabel { func sizeToFitHeight() { let maxHeight : CGFloat = CGFloat.greatestFiniteMagnitude let size = CGSize.init(width: self.frame.size.width, height: maxHeight) let rect = self.attributedText?.boundingRect(with: size, options: .usesLineFragmentOrigin, context: nil) var frame = self.frame frame.size.height = (rect?.size.height)! self.frame = frame } }