web-dev-qa-db-fra.com

Remplacement pour obsolète sizeWithFont: dans iOS 7?

Dans iOS 7, sizeWithFont: est maintenant obsolète. Comment je passe maintenant l'objet UIFont dans la méthode de remplacement sizeWithAttributes:?

319
James Kuang

Utilisez sizeWithAttributes: à la place, qui prend maintenant un NSDictionary. Passez la paire avec la clé UITextAttributeFont et votre objet police comme ceci:

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));
520
James Kuang

Je crois que la fonction a été déconseillée car cette série de fonctions NSString+UIKit (sizewithFont:..., etc.) était basée sur la bibliothèque UIStringDrawing, qui n'était pas thread-safe. Si vous essayez de ne pas les exécuter sur le thread principal (comme toute autre fonctionnalité UIKit), vous obtiendrez des comportements imprévisibles. En particulier, si vous avez exécuté la fonction simultanément sur plusieurs threads, votre application va probablement se bloquer. C'est pourquoi dans iOS 6, ils ont introduit la méthode boundingRectWithSize:... pour NSAttributedString. Ceci a été construit sur les bibliothèques NSStringDrawing et est thread-safe.

Si vous regardez la nouvelle fonction NSStringboundingRectWithSize:..., elle demande un tableau d'attributs de la même manière qu'un NSAttributeString. Si je devais deviner, cette nouvelle fonction NSString dans iOS 7 est simplement un wrapper pour la fonction NSAttributeString d’IOS 6.

Sur cette note, si vous ne supportiez que iOS 6 et iOS 7, je modifierais définitivement tous vos NSStringsizeWithFont:... en NSAttributeStringboundingRectWithSize. Cela vous épargnera beaucoup de maux de tête s'il vous arrive d'avoir un étrange cas d'angle multi-threading! Voici comment j'ai converti NSStringsizeWithFont:constrainedToSize::

Qu'est-ce que c'était:

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

Peut être remplacé par:

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;

Veuillez noter que la documentation mentionne:

Dans iOS 7 et versions ultérieures, cette méthode retourne des tailles fractionnaires (dans le composant size du fichier retourné CGRect); Pour utiliser une taille renvoyée, vous devez utiliser une valeur supérieure à l'entier le plus proche, à l'aide de la fonction ceil.

Donc, pour extraire la hauteur ou la largeur calculée à utiliser pour le dimensionnement des vues, je voudrais utiliser:

CGFloat height = ceilf(size.height);
CGFloat width  = ceilf(size.width);
172
Mr. T

Comme vous pouvez le voir sizeWithFont sur Apple Developer site, il est obsolète et nous devons donc utiliser 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]}];
}
29
Ayush

J'ai créé une catégorie pour gérer ce problème, la voici:

#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 cette façon, il vous suffit de rechercher/remplacer sizeWithFont: par sizeWithMyFont: et vous êtes prêt à partir.

16
Rom.

Dans iOS7, j'avais besoin de la logique pour renvoyer la hauteur correcte pour la vue tableau: heightForRowAtIndexPath, mais la méthode sizeWithAttributes renvoie toujours la même hauteur quelle que soit la longueur de la chaîne, car elle ne sait pas qu'elle sera placée dans une cellule de table à largeur fixe. . J'ai trouvé que cela fonctionne très bien pour moi et calcule la hauteur correcte en tenant compte de la largeur de la cellule de table! Ceci est basé sur la réponse de M. T. ci-dessus.

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
user3055587

Les étiquettes multilignes utilisant une hauteur dynamique peuvent nécessiter des informations supplémentaires pour définir la taille correctement. Vous pouvez utiliser sizeWithAttributes avec UIFont et NSParagraphStyle pour spécifier à la fois la police et le mode de saut de ligne.

Vous définiriez le style de paragraphe et utiliseriez un NSDictionary comme ceci:

// 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];

Vous pouvez utiliser CGSize'justSize 'ou CGRect comme propriété rect.size.height si vous recherchez la hauteur.

Plus d'infos sur NSParagraphStyle ici: https://developer.Apple.com/library/mac/documentation/cocoa/reference/applicationkit/classes/NSParagraphStyle_Class/Reference/Reference.html

7
bitsand
// 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));
5
Kirit Vaghela

Solution alternative-

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
DareDevil

S'appuyant sur @bitsand, il s'agit d'une nouvelle méthode que je viens d'ajouter à ma catégorie 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;
}

Je viens d'utiliser la taille du cadre résultant.

3
Chris Prince

Créez une fonction qui prend une instance de UILabel. et retourne 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
Muhammad Idris

Vous pouvez toujours utiliser sizeWithFont. mais, dans iOS> = 7.0, la méthode provoque le blocage de la chaîne si elle contient des espaces ou des lignes de fin et de fin \n.

Couper le texte avant de l'utiliser

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

Cela peut également s'appliquer à sizeWithAttributes et [label sizeToFit].

de plus, chaque fois que vous avez nsstringdrawingtextstorage message sent to deallocated instance dans un appareil iOS 7.0, il gère cela.

2
hasan

Mieux utiliser les dimensions automatiques (Swift):

  tableView.estimatedRowHeight = 68.0
  tableView.rowHeight = UITableViewAutomaticDimension

NB: 1. Le prototype UITableViewCell doit être correctement conçu (pour l'instance, n'oubliez pas de définir UILabel.numberOfLines = 0, etc.) 2. Supprimez la méthode HeightForRowAtIndexPath.

enter image description here

VIDÉO: https://youtu.be/Sz3XfCsSb6k

2
Eugene Braginets

Réponse acceptée dans Xamarin serait (utilisez sizeWithAttributes et UITextAttributeFont):

        UIStringAttributes attributes = new UIStringAttributes
        { 
            Font = UIFont.SystemFontOfSize(17) 
        }; 
        var size = text.GetSizeUsingAttributes(attributes);
1
Alex Sorokoletov
boundingRectWithSize:options:attributes:context:
1
Holden

Essayez cette syntaxe:

NSAttributedString *attributedText =
    [[NSAttributedString alloc] initWithString:text 
                                    attributes:@{NSFontAttributeName: font}];
0
Muruganandam.S

Comme le répond @ Ayush:

Comme vous pouvez le constater sizeWithFont sur le site de développeur Apple, il est obsolète et nous devons donc utiliser sizeWithAttributes .

Supposons qu’en 2019+ vous utilisiez probablement Swift et String au lieu d’Objective-c et NSString, voici la bonne façon d’obtenir la taille d’un String avec police prédéfinie:

let stringSize = NSString(string: label.text!).size(withAttributes: [.font : UIFont(name: "OpenSans-Regular", size: 15)!])
0
Romulo BM

Voici l'équivalent monotouch si quelqu'un en a besoin:

/// <summary>
/// Measures the height of the string for the given width.
/// </summary>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="width">The width.</param>
/// <param name="padding">The padding.</param>
/// <returns></returns>
public static float MeasureStringHeightForWidth(this string text, UIFont font, float width, float padding = 20)
{
    NSAttributedString attributedString = new NSAttributedString(text, new UIStringAttributes() { Font = font });
    RectangleF rect = attributedString.GetBoundingRect(new SizeF(width, float.MaxValue), NSStringDrawingOptions.UsesLineFragmentOrigin, null);
    return rect.Height + padding;
}

qui peut être utilisé comme ceci:

public override float GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
{
    //Elements is a string array
    return Elements[indexPath.Row].MeasureStringHeightForWidth(UIFont.SystemFontOfSize(UIFont.LabelFontSize), tableView.Frame.Size.Width - 15 - 30 - 15);
}
0
Roosevelt
CGSize maximumLabelSize = CGSizeMake(label.frame.size.width, FLT_MAX);
CGSize expectedLabelSize = [label sizeThatFits:maximumLabelSize];
float heightUse = expectedLabelSize.height;
0
user1802778
- (CGSize) sizeWithMyFont:(UIFont *)fontToUse
{
    if ([self respondsToSelector:@selector(sizeWithAttributes:)])
    {
        NSDictionary* attribs = @{NSFontAttributeName:fontToUse};
        return ([self sizeWithAttributes:attribs]);
    }
    return ([self sizeWithFont:fontToUse]);
}
0
Prosenjit Goswami