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?

Nirav Jain
fuente
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];
Quang Hà
fuente
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];
Maxim Pavlov
fuente
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.

Rikco
fuente
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}];
vinaut
fuente
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);
Myrddin
fuente
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.

Pratik
fuente