Dans iOS 7, sizeWithFont:
est maintenant obsolète. Comment je passe maintenant l'objet UIFont dans la méthode de remplacement sizeWithAttributes:
?
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));
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 NSString
boundingRectWithSize:...
, 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 NSString
sizeWithFont:...
en NSAttributeString
boundingRectWithSize
. 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 NSString
sizeWithFont: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);
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]}];
}
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.
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
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
// 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));
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];
}
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.
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;
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.
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.
VIDÉO: https://youtu.be/Sz3XfCsSb6k
Réponse acceptée dans Xamarin serait (utilisez sizeWithAttributes et UITextAttributeFont):
UIStringAttributes attributes = new UIStringAttributes
{
Font = UIFont.SystemFontOfSize(17)
};
var size = text.GetSizeUsingAttributes(attributes);
boundingRectWithSize:options:attributes:context:
Essayez cette syntaxe:
NSAttributedString *attributedText =
[[NSAttributedString alloc] initWithString:text
attributes:@{NSFontAttributeName: font}];
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 utilisersizeWithAttributes
.
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)!])
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);
}
CGSize maximumLabelSize = CGSizeMake(label.frame.size.width, FLT_MAX);
CGSize expectedLabelSize = [label sizeThatFits:maximumLabelSize];
float heightUse = expectedLabelSize.height;
- (CGSize) sizeWithMyFont:(UIFont *)fontToUse
{
if ([self respondsToSelector:@selector(sizeWithAttributes:)])
{
NSDictionary* attribs = @{NSFontAttributeName:fontToUse};
return ([self sizeWithAttributes:attribs]);
}
return ([self sizeWithFont:fontToUse]);
}