ios - Cálculo del tamaño del texto UILabel
objective-c frame (9)
Al usar esta línea de código, podemos obtener el tamaño del texto en la etiqueta.
let str = "Sample text"
let size = str.sizeWithAttributes([NSFontAttributeName:UIFont.systemFontOfSize(17.0)])
Entonces, podemos usar tanto el ancho como la altura.
Estoy dibujando UILabels
programáticamente. Obtienen sus tamaños de una base de datos. Entonces no puedo usar sizeToFit
. Ya he implementado una función que vuelve a dibujar UILabels
con una proporción aprobada. Entonces, todo lo que necesito encontrar es el texto en UILabel
desde mi punto de vista que requeriría la relación máxima para volver a dibujar UILabels
. Así que finalmente necesito hacer algo como esto:
double ratio = 1.00;
for (UILabel* labels in sec.subviews) {
float widthLabel = labels.frame.size.width;
float heightLabel = labels.frame.size.height;
float heightText = //get the text height here
float widthText = //get the text width here
if (widthLabel < widthText) {
ratio = MAX(widthText/widthLabel,ratio);
}
if (heightLabel < heightText) {
ratio = MAX(heightText/heightLabel, ratio);
}
}
//redraw UILabels with the given ratio here
Entonces, ¿cómo puedo obtener el tamaño de alto y ancho de un texto, como parte del texto no cabe en la etiqueta, no puedo simplemente usar límites de etiqueta? Estoy usando Xcode 5 y iOS 7.
Aquí hay una variante rápida.
let font = UIFont(name: "HelveticaNeue", size: 25)!
let text = "This is some really long text just to test how it works for calculating heights in swift of string sizes. What if I add a couple lines of text?"
let textString = text as NSString
let textAttributes = [NSFontAttributeName: font]
textString.boundingRectWithSize(CGSizeMake(320, 2000), options: .UsesLineFragmentOrigin, attributes: textAttributes, context: nil)
El problema con
CGRect r = [text boundingRectWithSize:CGSizeMake(200, 0)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:fontSize]}
context:nil];
es boundingRectWithSize
que determina el valor máximo que puede tener CGRect.
Mi solución para este problema es verificar si excede, si no, el texto puede caber en la etiqueta. Lo hice usando bucles.
NSString *text = @"This is a long sentence. Wonder how much space is needed?";
CGFloat width = 100;
CGFloat height = 100;
bool sizeFound = false;
while (!sizeFound) {
NSLog(@"Begin loop");
CGFloat fontSize = 14;
CGFloat previousSize = 0.0;
CGFloat currSize = 0.0;
for (float fSize = fontSize; fSize < fontSize+6; fSize++) {
CGRect r = [text boundingRectWithSize:CGSizeMake(width, height)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:fSize]}
context:nil];
currSize =r.size.width*r.size.height;
if (previousSize >= currSize) {
width = width*11/10;
height = height*11/10;
fSize = fontSize+10;
}
else {
previousSize = currSize;
}
NSLog(@"fontSize = %f/tbounds = (%f x %f) = %f",
fSize,
r.size.width,
r.size.height,r.size.width*r.size.height);
}
if (previousSize == currSize) {
sizeFound = true;
}
}
NSLog(@"Size found with width %f and height %f", width, height);
Después de cada iteración, el tamaño de la altura y el ancho incrementa el 10% de su valor.
La razón por la que elegí 6 es porque no quería que la etiqueta fuera demasiado blanda.
Para una solución que no usa bucles:
NSString *text = @"This is a long sentence. Wonder how much space is needed?";
CGFloat width = 100;
CGFloat height = 100;
CGFloat currentFontSize = 12;
CGRect r1 = [text boundingRectWithSize:CGSizeMake(width, height)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:currentFontSize+6]}
context:nil];
CGRect r2 = [text boundingRectWithSize:CGSizeMake(width, height)
options:NSStringDrawingUsesFontLeading
attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:currentFontSize+6]}
context:nil];
CGFloat firstVal =r1.size.width*r1.size.height;
CGFloat secondVal =r2.size.width*r2.size.height;
NSLog(@"First val %f and second val is %f", firstVal, secondVal);
if (secondVal > firstVal) {
float initRat = secondVal/firstVal;
float ratioToBeMult = sqrtf(initRat);
width *= ratioToBeMult;
height *= ratioToBeMult;
}
NSLog(@"Final width %f and height %f", width, height);
//for verifying
for (NSNumber *n in @[@(12.0f), @(14.0f), @(17.0f)]) {
CGFloat fontSize = [n floatValue];
CGRect r = [text boundingRectWithSize:CGSizeMake(width, height)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:fontSize]}
context:nil];
NSLog(@"fontSize = %f/tbounds = (%f x %f) = %f",
fontSize,
r.size.width,
r.size.height,r.size.width*r.size.height);
firstVal =r.size.width*r.size.height;
}
Donde el último ciclo es la prueba de que una fuente más grande puede dar un resultado de mayor tamaño.
Length obtiene la cantidad de caracteres. Si quieres obtener el ancho del texto:
C objetivo
CGSize textSize = [label.text sizeWithAttributes:@{NSFontAttributeName:[label font]}];
Swift 4
let size = label.text?.size(withAttributes: [.font: label.font]) ?? .zero
Esto te da el tamaño. Y puede comparar textSize.width
de cada etiqueta.
Otra forma simple de hacer esto que no he visto mencionar aún:
CGSize textSize = [label intrinsicContentSize];
(Esto solo funciona correctamente después de haber establecido el texto y la fuente de la etiqueta, por supuesto).
Pequeños consejos chicos, si como yo estás usando, boundingRectWithSize
con [UIFont systemFontOFSize:14]
Si su cadena tiene dos líneas, la altura rectificada es aproximadamente 33,4 puntos.
No cometas el error, como yo, de convertirlo en int
, porque 33,4 pasa a ser 33, y 33 puntos de altura pasan de dos a una línea.
Todos los [NSString sizeWithFont...]
están en desuso en iOS 7. Use esto en su lugar.
CGRect labelRect = [text
boundingRectWithSize:labelSize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{
NSFontAttributeName : [UIFont systemFontOfSize:14]
}
context:nil];
También vea https://developer.apple.com/documentation/foundation/nsstring/1619914-sizewithfont .
ACTUALIZACIÓN: ejemplo de salida boundingRectWithSize
Por su comentario hice una prueba simple. El código y la salida están debajo.
// code to generate a bounding rect for text at various font sizes
NSString *text = @"This is a long sentence. Wonder how much space is needed?";
for (NSNumber *n in @[@(12.0f), @(14.0f), @(18.0f)]) {
CGFloat fontSize = [n floatValue];
CGRect r = [text boundingRectWithSize:CGSizeMake(200, 0)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:fontSize]}
context:nil];
NSLog(@"fontSize = %f/tbounds = (%f x %f)",
fontSize,
r.size.width,
r.size.height);
}
esto produce el siguiente resultado (tenga en cuenta que los límites cambian según lo esperado a medida que el tamaño de la fuente se hace más grande):
fontSize = 12.000000 bounds = (181.152008 x 28.632000)
fontSize = 14.000000 bounds = (182.251999 x 50.105999)
fontSize = 18.000000 bounds = (194.039993 x 64.421997)
msgStr string obtener tamaño:
let msgStr:NSString = Data["msg"]! as NSString
let messageSize = msgStr.boundingRect(with: CGSize(width: ChatTable.frame.width-116, height: CGFloat.infinity), options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName:UIFont(name: "Montserrat-Light", size: 14)!], context: nil).size
Swift 3.0
func getLabelHeight() -> CGFloat {
let font = UIFont(name: "OpenSans", size: 15)!
let textString = "Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." as NSString
let textAttributes = [NSFontAttributeName: font]
let rect = textString.boundingRect(with: CGSize(width: 320, height: 2000), options: .usesLineFragmentOrigin, attributes: textAttributes, context: nil)
return rect.size.height
}