Cálculo del tamaño del texto UILabel

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.

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 = (%fx %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) 

Length obtiene la cantidad de caracteres. Si quieres obtener el ancho del texto:

C objective

 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).

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) 

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.

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 = (%fx %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 = (%fx %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 letra más grande puede dar un resultado de mayor tamaño.

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.

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 }