El método sizeWithFont está en desuso. boundingRectWithSize devuelve un valor inesperado


82

En iOS7, sizeWithFontestá en desuso, por lo que estoy usando boundingRectWithSize(que devuelve un valor CGRect). Mi código:

 UIFont *fontText = [UIFont fontWithName:[AppHandlers zHandler].fontName size:16];
                    // you can use your font.

 CGSize maximumLabelSize = CGSizeMake(310, 9999);

 CGRect textRect = [myString boundingRectWithSize:maximumLabelSize   
                             options:NSStringDrawingUsesLineFragmentOrigin
                             attributes:@{NSFontAttributeName:fontText}
                             context:nil];

 expectedLabelSize = CGSizeMake(textRect.size.width, textRect.size.height);

En textRect, obtengo un tamaño mayor que el mío maximumLabelSize, un tamaño diferente al que usé sizeWithFont. ¿Cómo puedo resolver este problema?


Tengo este problema con todas las fuentes, no solo con la fuente del sistema o Helvetica.
Nirav Jain

¿tienes alguna idea de cómo hacer eso?
Nirav Jain

Puede resultar útil un ejemplo concreto de nombre de fuente, texto y tamaños que no coinciden.
Eiko

Solía ​​usar CTFramesetterSuggestFrameSizeWithConstraints en iOS6 para calcular la altura de la cadena atribuida que siempre devuelve la altura correcta. En iOS7, tanto CTFramesetterSuggestFrameSizeWithConstraints como boundingRectWithSize me dan un resultado de altura incorrecto. Apuesto a que es un error introducido en iOS7 y parece que todavía no hay solución.
Arnold Tang

También estoy enfrentando el mismo problema, es mejor usar tttattributedlabel
Sri ..

Respuestas:


151

¿Qué tal crear una nueva etiqueta y usarla sizeThatFit:(CGSize)size?

UILabel *gettingSizeLabel = [[UILabel alloc] init];
gettingSizeLabel.font = [UIFont fontWithName:@"YOUR FONT's NAME" size:16];
gettingSizeLabel.text = @"YOUR LABEL's TEXT";
gettingSizeLabel.numberOfLines = 0;
gettingSizeLabel.lineBreakMode = NSLineBreakByWordWrapping;
CGSize maximumLabelSize = CGSizeMake(310, CGFLOAT_MAX);

CGSize expectSize = [gettingSizeLabel sizeThatFits:maximumLabelSize];

Editar: este código superior no es bueno para ios 7 y superior, así que utilícelo a continuación:

CGRect textRect = [myString boundingRectWithSize:maximumLabelSize   
                         options:NSStringDrawingUsesLineFragmentOrigin| NSStringDrawingUsesFontLeading
                         attributes:@{NSFontAttributeName:fontText}
                         context:nil];

este método no funciona cuando agrego entidades HTML como (<OL>, <LI>) en una cadena.
Nirav Jain

por favor revisa mi respuesta de nuevo! ¡Me perdí la propiedad de numberOfLines! ¡lo siento!
Quang Hà

1
Después de horas y horas de búsqueda, experimentación y callejones sin salida, esta es la única solución que funciona para iOS7 y Xamarin / Monotouch
Michael Rodrigues

26
¿Creando una etiqueta para calcular el tamaño de la fuente? ¡Eso es un desperdicio!
Ossir

13
@Ossir, ¿tienes una idea mejor?
Luda

36

Tal vez necesite proporcionar una opción adicional al método que se sugiere en esta respuesta:

CGSize maximumLabelSize = CGSizeMake(310, CGFLOAT_MAX);
CGRect textRect = [myString boundingRectWithSize:maximumLabelSize   
                                         options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                      attributes:@{NSFontAttributeName: fontText}
                                         context:nil];

3
Parece que boundingRectWithSizeestá roto. Probé en iOS 7, 7.1.1 y no devuelve resultados correctos.
RaffAl

Esto no funcionó para mí, sin embargo, el uso de boundingRectWithSize en un NSAttributedString y la adición de mi atributo de fuente a la cadena funcionó.
Sheepdogsheep

12
Chicos, no se olviden de la declaración de Apple: en iOS 7 y posterior, este método devuelve tamaños fraccionarios (en el componente de tamaño del CGRect devuelto); para usar un tamaño devuelto para dimensionar vistas, debe usar aumentar su valor al número entero más alto más cercano usando la función ceil.
SoftDesigner

2
ceil no fue suficiente para mí, pero descubrí que usar ceil y también agregar 0.5 funcionó
dwery

15

Aquí está mi fragmento de código de trabajo:

NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:attributeDict];

NSString *headline  = [dict objectForKey:@"title"];  
UIFont *font        = [UIFont boldSystemFontOfSize:18];  
CGRect  rect        = [headline boundingRectWithSize:CGSizeMake(300, 1000) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:font} context:nil];

CGFloat height      = roundf(rect.size.height +4)

Agregué 4px a la altura calculada, porque sin estos 4px, falta una línea.

Utilizo este fragmento de código en un tableView y agrego la "altura" a una matriz de NSNumbers y obtengo la altura de celda correcta para la etiqueta de texto predeterminada.

Agregue 4 píxeles más si desea más espacio debajo del texto en la etiqueta de texto.

**** ACTUALIZACIÓN ****

No estoy de acuerdo con el "error de ancho de 40px", grito que sean los 4px de altura que faltan, porque 4px es la altura predeterminada de un espacio entre una letra y el límite de una sola línea. Puede comprobarlo con una UILabel, para un tamaño de fuente de 16 necesita una altura de UILabel de 20.

Pero si su última línea no tiene "g" o lo que sea, la medición podría perder los 4px de altura.

Lo volví a verificar con un pequeño método, obtengo una altura precisa de 20,40 o 60 para mi etiqueta y un ancho correcto de menos de 300px.

Para admitir iOS6 e iOS7, puede usar mi método:

- (CGFloat)heightFromString:(NSString*)text withFont:(UIFont*)font constraintToWidth:(CGFloat)width
{
    CGRect rect;

    float iosVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
    if (iosVersion >= 7.0) {
        rect = [text boundingRectWithSize:CGSizeMake(width, 1000) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:font} context:nil];
    }
    else {
        CGSize size = [text sizeWithFont:font constrainedToSize:CGSizeMake(width, 1000) lineBreakMode:NSLineBreakByWordWrapping];
        rect = CGRectMake(0, 0, size.width, size.height);
    }
    NSLog(@"%@: W: %.f, H: %.f", self, rect.size.width, rect.size.height);
    return rect.size.height;
}

**** POTENCIAR ****

Gracias a sus comentarios, actualicé mi función de la siguiente manera. Dado que sizeWithFont está en desuso y recibirá una advertencia en XCode, agregué el diagnóstico-pragma-code para eliminar la advertencia para esta función / bloque de código en particular.

- (CGFloat)heightFromStringWithFont:(UIFont*)font constraintToWidth:(CGFloat)width
{
    CGRect rect;

    if ([self respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]) {
        rect = [self boundingRectWithSize:CGSizeMake(width, 1000) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:font} context:nil];
    }
    else {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
        CGSize size = [self sizeWithFont:font constrainedToSize:CGSizeMake(width, 1000) lineBreakMode:NSLineBreakByWordWrapping];
        rect = CGRectMake(0, 0, size.width, size.height);
#pragma GCC diagnostic pop
    }
    return ceil(rect.size.height);
}

Además del tema 4px: dependiendo de la fuente y el peso de la fuente que use, el cálculo devuelve diferentes valores de altura. En mi caso: HelveticaNeue-Medium con un tamaño de fuente de 16.0 devuelve una altura de línea de 20.0 para una sola línea pero 39.0 para dos líneas, 78px para 4 líneas -> falta 1px para cada línea - comenzando con la línea 2 - pero quieres para tener su tamaño de fuente + espacio de línea de 4px para cada línea, debe obtener un resultado de altura.
¡Tenga esto en cuenta mientras codifica!
Todavía no tengo una función para este "problema" pero actualizaré esta publicación cuando termine.


1
Probablemente debería usar [text respondsToSelector: @selector (boundingRectWithSize: options: atributos: context :)] en lugar de verificar un valor flotante.
Samah

1
Es mejor usar la función ceil en lugar de + 4pt, mira esta respuesta stackoverflow.com/a/23563152/667483
surfrider

2

Si lo entiendo correctamente, está utilizando boundingRectWithSize: solo como una forma de obtener el tamaño que obtendría con sizeWithFont (lo que significa que desea directamente CGSize, no CGRect).

Esto se parece a lo que está buscando:

Reemplazo de sizeWithFont obsoleto: ¿en iOS 7?

Están usando sizeWithAttributes: para obtener el tamaño, como reemplazo de sizeWithFont.

¿Todavía obtienes el tamaño incorrecto usando algo como esto:

UIFont *fontText = [UIFont fontWithName:[AppHandlers zHandler].fontName size:16];
                    // you can use your font.

expectedLabelSize = [myString sizeWithAttributes:@{NSFontAttributeName:fontText}];

pero ¿cómo puedo usar CGSize maximumLabelSize = CGSizeMake (310, 9999)? Necesito la altura y el ancho correctos.
Nirav Jain

1
¿Hay algún atributo que le diga a sizeWithAttributes: restringir su ancho / alto?
Nirav Jain

Lo siento, pero no entiendo cuál es tu problema. Desea ajustar el tamaño de la etiqueta con el tamaño de la fuente, pero no más de una altura máxima, si entiendo correctamente. Dices que puedes hacer eso con sizeWithFont, pero quieres una alternativa ahora que este método está obsoleto, ¿correcto? Debería poder conectar sizeWithAttribues: de la misma manera que estaba usando sizeWithFont:. ¿Cómo restringía el tamaño de la etiqueta cuando usaba sizeWithFont? ¿Puedes publicar el código que te estaba funcionando usando sizeWithFont?
vinaut

2
Estaba usando sizeWithFont: constrainedToSize: lineBreakMode: y no hay forma de pasar el valor constrainedToSize a sizeWithAttributes.
zh.

2

El comentario de @ SoftDesigner me ha funcionado

CGRect descriptionRect = [description boundingRectWithSize:CGSizeMake(width, 0)
                                                       options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                                    attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:12]}
                                                       context:nil];
result = ceil(descriptionRect.size.height);

1

para encontrar el tamaño del tiempo de ejecución de la etiqueta, sizewithfont está en desuso para iOS 7.0 en lugar de eso, debe usar -boundingRectWithSize: options: attribute: context: method

puedes usarlo como el siguiente código

CGSize constraint = CGSizeMake(MAXIMUM_WIDHT, TEMP_HEIGHT);
NSRange range = NSMakeRange(0, [[self.message body] length]);

NSDictionary *attributes = [YOUR_LABEL.attributedText attributesAtIndex:0 effectiveRange:&range];
CGSize boundingBox = [myString boundingRectWithSize:constraint options:NSStringDrawingUsesFontLeading attributes:attributes context:nil].size;
int numberOfLine = ceil((boundingBox.width) / YOUR_LABEL.frame.size.width);
CGSize descSize = CGSizeMake(ceil(boundingBox.width), ceil(self.lblMessageDetail.frame.size.height*numberOfLine));

CGRect frame=YOUR_LABEL.frame;
frame.size.height=descSize.height;
YOUR_LABEL.frame=frame;

aquí tienes que dar ancho a la longitud máxima para encontrar la altura o el ancho.

prueba esto, me está funcionando.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.