iPhone UILabel sizeWithFont:
-
05-07-2019 - |
Pregunta
Estoy tratando de medir el tamaño visual de una NSString que tenga en cuenta el número de líneas que puedo representar. Sin embargo, sizeWithFont no tiene en cuenta la propiedad numberOfLines? Así que mi algoritmo de diseño posiciona todo lo más bajo de lo que realmente debe ser.
_price = [[UILabel alloc] init];
_price.text = myPriceValue;
_price.lineBreakMode = UILineBreakModeWordWrap;
_price.numberOfLines = 3;
_price.backgroundColor = [UIColor clearColor];
_price.textColor = TTSTYLEVAR(colorPrice);
/// the follow code ignores numberOfLines and just tells me the size of the whole block.
// I'd like it to be aware of numberOfLines
//
CGSize priceSize = [_price.text sizeWithFont:_price.font
constrainedToSize:CGSizeMake(maxWidth, CGFLOAT_MAX)
lineBreakMode:UILineBreakModeWordWrap];
¿Alguien sabe cómo hacerlo usando el iPhone SDK?
Solución
En lugar de CGFLOAT_MAX para la altura máxima de su cálculo de texto, intente obtener el tamaño de una línea con esto:
[_price.text sizeWithFont:_price.font].height
y luego multiplique eso por el número máximo de líneas que desea, luego conéctelo a la altura del tamaño al que se está limitando. Probablemente se vería así:
_price = [[UILabel alloc] init];
_price.text = myPriceValue;
_price.lineBreakMode = UILineBreakModeWordWrap;
_price.numberOfLines = 3;
_price.backgroundColor = [UIColor clearColor];
_price.textColor = TTSTYLEVAR(colorPrice);
CGFloat lineHeight = [_price.text sizeWithFont:_price.font].height;
CGSize priceSize = [_price.text sizeWithFont:_price.font
constrainedToSize:CGSizeMake(maxWidth, lineHeight * _price.numberOfLines)
lineBreakMode:UILineBreakModeWordWrap];
No use esto si alguna vez establece el número de líneas en 0, ya que su altura máxima será 0 en ese caso; deberías usar CGFLOAT_MAX entonces.
Otros consejos
Utilice sizeToFit de UILabel en lugar de sizeWithFont: para diseñar una UILabel multilínea, ya que sizeWithFont: truncará la cadena (consulte los documentos de Apple). El siguiente código reduce el tamaño de fuente de una etiqueta hasta que el texto se ajuste al tamaño especificado ... se usarán varias líneas de texto tan pronto como se ajusten a la altura especificada:
-(void)setFontSizeOfMultiLineLabel: (UILabel*)label
toFitSize: (CGSize) size
forMaxFontSize: (CGFloat) maxFontSize
andMinFontSize: (CGFloat) minFontSize
startCharacterWrapAtSize: (CGFloat)characterWrapSize{
CGRect constraintSize = CGRectMake(0, 0, size.width, 0);
label.frame = constraintSize;
label.lineBreakMode = UILineBreakModeWordWrap;
label.numberOfLines = 0; // allow any number of lines
for (int i = maxFontSize; i > minFontSize; i--) {
if((i < characterWrapSize) && (label.lineBreakMode == UILineBreakModeWordWrap)){
// start over again with lineBreakeMode set to character wrap
i = maxFontSize;
label.lineBreakMode = UILineBreakModeCharacterWrap;
}
label.font = [label.font fontWithSize:i];
[label sizeToFit];
if(label.frame.size.height < size.height){
break;
}
label.frame = constraintSize;
}
}
Llámalo con una etiqueta que tenga tu texto y fuente favoritos:
UILabel *label = [[UILabel alloc] initWithFrame: CGRectZero];
label.backgroundColor = [UIColor clearColor];
label.textColor = [UIColor whiteColor];
label.text = text;
label.font = [UIFont fontWithName: @"Helvetica" size: 16];
[self setFontSizeOfMultiLineLabel: label toFitSize: CGSizeMake(200, 44) forMaxFontSize: 16 andMinFontSize: 8 startCharacterWrapAtSize: 11];
El parámetro startCharacterWrapAtSize le permite elegir usar characterWrap comenzando en el tamaño de fuente dado. Esto debería ahorrar espacio en el caso de que wordWrap use fuentes realmente pequeñas.
editar: corrección de errores
En lugar de intentar hacerlo en una llamada, haga algo como esto (perdone el pseudocódigo, es tarde):
NSString *s = _price.text;
UIFont *font = _price.font;
CGFloat fontSize = font.pointSize;
while (TRUE)
{
CGSize priceSize = [s sizeWithFont: font constrainedToSize:
CGSizeMake(maxWidth, fontSize) lineBreakMode: UILineBreakModeWordWrap];
if ( /* priceSize is satisfactory */ )
{
break; // Make sure this exits, eventually!!!
}
fontSize -= 1.0; // or a smaller decrement if you like
font = // new, smaller font
}
La respuesta correcta es, por supuesto, que debe establecer numberOfLines en 0, lo que hará que el marco calcule el resultado con la cantidad de líneas que necesite. Consulte también esta pregunta .
Por supuesto que no lo tiene en cuenta, ya que nada de lo que se llama o se pasa tiene esa información. Estás trabajando estrictamente con cadenas, tamaños y fuentes. Es la etiqueta que tiene el número de líneas.
No estoy seguro de cuál es exactamente tu problema; ¿estás obteniendo una talla demasiado alta o demasiado corta, o qué? Puede averiguar el número de líneas de texto dividiendo la altura del resultado por la altura de la fuente, que es el valor del ascendente más el descendente, creo.