Reemplazo para sizeWithFont obsoleto: en iOS 7?


En iOS 7, sizeWithFont: ahora está obsoleto. ¿Cómo paso ahora el objeto UIFont al método de reemplazo sizeWithAttributes:?

Author: James Kuang, 0000-00-00

12 answers

Use sizeWithAttributes: en su lugar, que ahora toma un NSDictionary. Pase el par con key UITextAttributeFont y su objeto de fuente de esta manera:

CGSize size = [string sizeWithAttributes:
    @{NSFontAttributeName: [UIFont systemFontOfSize:17.0f]}];

// Values are fractional -- you should take the ceilf to get equivalent values
CGSize adjustedSize = CGSizeMake(ceilf(size.width), ceilf(size.height));
 515
Author: James Kuang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-15 10:01:39

Creo que la función fue obsoleta porque esa serie de funciones NSString+UIKit (sizewithFont:..., etc.) se basaban en la biblioteca UIStringDrawing, que no era segura para subprocesos. Si intentaste ejecutarlos no en el hilo principal (como cualquier otra funcionalidad UIKit), obtendrás comportamientos impredecibles. En particular, si ejecutaste la función en varios subprocesos simultáneamente, probablemente bloqueará tu aplicación. Es por eso que en iOS 6, introdujeron un método boundingRectWithSize:... para NSAttributedString. Esto fue construido en la parte superior de la NSStringDrawing bibliotecas y es hilo seguro.

Si nos fijamos en el nuevo NSString boundingRectWithSize:... función, pide una matriz de atributos de la misma manera que un NSAttributeString. Si tuviera que adivinar, esta nueva función NSString en iOS 7 es simplemente un envoltorio para la función NSAttributeString de iOS 6.

En esa nota, si solo estuviera soportando iOS 6 e iOS 7, entonces definitivamente cambiaría todo su NSString sizeWithFont:... a la NSAttributeString boundingRectWithSize. Te ahorrará un montón de dolor de cabeza si tienes un extraño multi-threading ¡corner case! Así es como me convertí NSString sizeWithFont:constrainedToSize::

Lo que solía ser:

NSString *text = ...;
CGFloat width = ...;
UIFont *font = ...;
CGSize size = [text sizeWithFont:font 
               constrainedToSize:(CGSize){width, CGFLOAT_MAX}];

Puede sustituirse por:

NSString *text = ...;
CGFloat width = ...;
UIFont *font = ...;
NSAttributedString *attributedText =
    [[NSAttributedString alloc] initWithString:text 
                                    attributes:@{NSFontAttributeName: font}];
CGRect rect = [attributedText boundingRectWithSize:(CGSize){width, CGFLOAT_MAX}
                                           options:NSStringDrawingUsesLineFragmentOrigin
                                           context:nil];
CGSize size = rect.size;

Tenga en cuenta la documentación menciona:

En iOS 7 y posteriores, este método devuelve tamaños fraccionados (en el tamaño componente del CGRect devuelto); para usar un tamaño devuelto a tamaño vistas, debe usar elevar su valor al entero más alto más cercano usando la función ceil.

Así que para sacar la altura o anchura calculada que se utilizará para dimensionar las vistas, usaría:

CGFloat height = ceilf(size.height);
CGFloat width  = ceilf(size.width);
 168
Author: Mr. T,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-06 18:23:31

Como puedes ver sizeWithFont en el sitio de desarrolladores de Apple está en desuso, por lo que necesitamos usar sizeWithAttributes.

#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)

NSString *text = @"Hello iOS 7.0";
if (SYSTEM_VERSION_LESS_THAN(@"7.0")) {
    // code here for iOS 5.0,6.0 and so on
    CGSize fontSize = [text sizeWithFont:[UIFont fontWithName:@"Helvetica" 
                                                         size:12]];
} else {
    // code here for iOS 7.0
   CGSize fontSize = [text sizeWithAttributes: 
                            @{NSFontAttributeName: 
                              [UIFont fontWithName:@"Helvetica" size:12]}];
}
 27
Author: Ayush,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-01 13:55:38

He creado una categoría para manejar este problema, aquí está :

#import "NSString+StringSizeWithFont.h"

@implementation NSString (StringSizeWithFont)

- (CGSize) sizeWithMyFont:(UIFont *)fontToUse
{
    if ([self respondsToSelector:@selector(sizeWithAttributes:)])
    {
        NSDictionary* attribs = @{NSFontAttributeName:fontToUse};
        return ([self sizeWithAttributes:attribs]);
    }
    return ([self sizeWithFont:fontToUse]);
}

De esta manera solo tienes que encontrar/reemplazar sizeWithFont: con sizeWithMyFont: y ya está listo.

 16
Author: Rom.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-25 15:53:54

En iOS7 necesitaba la lógica para devolver la altura correcta para el método tableview:heightForRowAtIndexPath, pero sizeWithAttributes siempre devuelve la misma altura independientemente de la longitud de la cadena porque no sabe que se va a poner en una celda de tabla de ancho fijo. Me pareció que esto funciona muy bien para mí y calcula la altura correcta teniendo en cuenta el ancho de la celda de la tabla! Esto se basa en la respuesta anterior del Sr. T.

NSString *text = @"The text that I want to wrap in a table cell."

CGFloat width = tableView.frame.size.width - 15 - 30 - 15;  //tableView width - left border width - accessory indicator - right border width
UIFont *font = [UIFont systemFontOfSize:17];
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:@{NSFontAttributeName: font}];
CGRect rect = [attributedText boundingRectWithSize:(CGSize){width, CGFLOAT_MAX}
                                           options:NSStringDrawingUsesLineFragmentOrigin
                                           context:nil];
CGSize size = rect.size;
size.height = ceilf(size.height);
size.width  = ceilf(size.width);
return size.height + 15;  //Add a little more padding for big thumbs and the detailText label
 10
Author: user3055587,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-26 02:13:52

Las etiquetas multilínea que utilizan altura dinámica pueden requerir información adicional para establecer el tamaño correctamente. Puede utilizar sizeWithAttributes con UIFont y NSParagraphStyle para especificar tanto la fuente como el modo de salto de línea.

Usted definiría el Estilo de Párrafo y usaría un NSDictionary como este:

// set paragraph style
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[style setLineBreakMode:NSLineBreakByWordWrapping];
// make dictionary of attributes with paragraph style
NSDictionary *sizeAttributes        = @{NSFontAttributeName:myLabel.font, NSParagraphStyleAttributeName: style};
// get the CGSize
CGSize adjustedSize = CGSizeMake(label.frame.size.width, CGFLOAT_MAX);

// alternatively you can also get a CGRect to determine height
CGRect rect = [myLabel.text boundingRectWithSize:adjustedSize
                                                         options:NSStringDrawingUsesLineFragmentOrigin
                                                      attributes:sizeAttributes
                                                         context:nil];

Puede usar el CGSize 'adjustedSize' o CGRect como rect.Tamaño.propiedad de altura si está buscando la altura.

Más información sobre NSParagraphStyle aquí: https://developer.apple.com/library/mac/documentation/cocoa/reference/applicationkit/classes/NSParagraphStyle_Class/Reference/Reference.html

 7
Author: bitsand,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-19 01:15:28
// max size constraint
CGSize maximumLabelSize = CGSizeMake(184, FLT_MAX)

// font
UIFont *font = [UIFont fontWithName:TRADE_GOTHIC_REGULAR size:20.0f];

// set paragraph style
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;

// dictionary of attributes
NSDictionary *attributes = @{NSFontAttributeName:font,
                             NSParagraphStyleAttributeName: paragraphStyle.copy};

CGRect textRect = [string boundingRectWithSize: maximumLabelSize
                                     options:NSStringDrawingUsesLineFragmentOrigin
                                  attributes:attributes
                                     context:nil];

CGSize expectedLabelSize = CGSizeMake(ceil(textRect.size.width), ceil(textRect.size.height));
 4
Author: Kirit Vaghela,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-28 11:52:09

Cree una función que tome una instancia de UILabel. y devuelve CGSize

CGSize constraint = CGSizeMake(label.frame.size.width , 2000.0);
// Adjust according to requirement

CGSize size;
if([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0){

    NSRange range = NSMakeRange(0, [label.attributedText length]);

    NSDictionary *attributes = [label.attributedText attributesAtIndex:0 effectiveRange:&range];
    CGSize boundingBox = [label.text boundingRectWithSize:constraint options: NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil].size;

    size = CGSizeMake(ceil(boundingBox.width), ceil(boundingBox.height));
}
else{
    size = [label.text sizeWithFont:label.font constrainedToSize:constraint lineBreakMode:label.lineBreakMode];
}

return size;
 3
Author: idris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-30 15:31:19

Solución alternativa-

CGSize expectedLabelSize;
if ([subTitle respondsToSelector:@selector(sizeWithAttributes:)])
{
    expectedLabelSize = [subTitle sizeWithAttributes:@{NSFontAttributeName:subTitleLabel.font}];
}else{
    expectedLabelSize = [subTitle sizeWithFont:subTitleLabel.font constrainedToSize:subTitleLabel.frame.size lineBreakMode:NSLineBreakByWordWrapping];
}
 3
Author: DareDevil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-10 07:22:45

Basado en @ bitsand, este es un nuevo método que acabo de agregar a mi categoría NSString + Extras:

- (CGRect) boundingRectWithFont:(UIFont *) font constrainedToSize:(CGSize) constraintSize lineBreakMode:(NSLineBreakMode) lineBreakMode;
{
    // set paragraph style
    NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
    [style setLineBreakMode:lineBreakMode];

    // make dictionary of attributes with paragraph style
    NSDictionary *sizeAttributes = @{NSFontAttributeName:font, NSParagraphStyleAttributeName: style};

    CGRect frame = [self boundingRectWithSize:constraintSize options:NSStringDrawingUsesLineFragmentOrigin attributes:sizeAttributes context:nil];

    /*
    // OLD
    CGSize stringSize = [self sizeWithFont:font
                              constrainedToSize:constraintSize
                                  lineBreakMode:lineBreakMode];
    // OLD
    */

    return frame;
}

Solo uso el tamaño del marco resultante.

 3
Author: Chris Prince,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-05 21:45:19

Todavía puedes usar sizeWithFont. pero, en el método iOS > = 7.0 causa un fallo si la cadena contiene espacios iniciales y finales o líneas finales \n.

Recortar texto antes de usarlo

label.text = [label.text stringByTrimmingCharactersInSet:
             [NSCharacterSet whitespaceAndNewlineCharacterSet]];

Eso también puede aplicarse a sizeWithAttributes y [label sizeToFit].

También, siempre que tenga nsstringdrawingtextstorage message sent to deallocated instance en el dispositivo iOS 7.0, se ocupa de esto.

 2
Author: hasan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-10 11:47:48

Utilice mejor las dimensiones automáticas (Swift):

  tableView.estimatedRowHeight = 68.0
  tableView.rowHeight = UITableViewAutomaticDimension

NB: 1. UITableViewCell prototype debe estar diseñado correctamente (para la instancia no olvide establecer UILabel.numberOfLines = 0 etc) 2. Remove heightForRowAtIndexPath method

introduzca la descripción de la imagen aquí

VÍDEO: https://youtu.be/Sz3XfCsSb6k

 2
Author: ,
Warning: date() expects parameter 2 to be long, string given in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61