J'ai une méthode qui me donne la taille parfaite pour un UITextView étant donné une longueur de chaîne (avec la taille de police correcte correspondante):
- (NSInteger) heightOfLabel:(NSString*) string {
CGSize maximumLabelSize = CGSizeMake([[UIScreen mainScreen] bounds].size.width - 40, FLT_MAX);
CGSize expectedLabelSize = [[NSString stringTrimmedForLeadingAndTrailingWhiteSpacesFromString:string]
sizeWithFont:[UIFont systemFontOfSize:15]
constrainedToSize:maximumLabelSize
lineBreakMode:NSLineBreakByWordWrapping];
return expectedLabelSize.height + 5;
}
En fait, cela me donne toujours un ajustement parfait, même dans iOS7. Bien que maintenant, il propose une méthode d'avertissement qui dit que je ne devrais pas utiliser 'sizeWithFont: contrainedToSize: lineBreakMode'.
Il dit maintenant que je devrais utiliser -boundingRectWithSize: options: attributes: context:
Cette méthode n'est pas nouvelle pour iOS7 et je pense donc qu'il est correct de la demander en cas de débordement de pile, plutôt que de passer au forum officiel des développeurs Apple Apple).
J'ai trois questions:
1) Parce qu'il est obsolète, cela signifie-t-il que je devrais définitivement le remplacer, même s'il fonctionne toujours?
2) J'ai essayé de nombreuses méthodes boundingRectWithSize différentes: avec diverses variables mais ce n'est jamais parfait, il semble toujours être légèrement en dehors (comme le soulignent de nombreuses questions de stackoverflow) - y a-t-il un remplacement parfait avec cette méthode non obsolète qui fait exactement la même que ma méthode précédente avec un minimum de tracas?
3) pourquoi supprimer cette méthode? Est-ce à cause du chevauchement avec cette autre méthode?
Après une heure d'erreur d'essai, j'ai réussi à le faire fonctionner:
CGSize maximumLabelSize = CGSizeMake(tableView.width, MAXFLOAT);
NSStringDrawingOptions options = NSStringDrawingTruncatesLastVisibleLine |
NSStringDrawingUsesLineFragmentOrigin;
NSDictionary *attr = @{NSFontAttributeName: [UIFont systemFontOfSize:15]};
CGRect labelBounds = [string boundingRectWithSize:maximumLabelSize
options:options
attributes:attr
context:nil];
Mise à jour:
Comme le mentionne M. T dans la réponse ci-dessous: dans iOS 7 et versions ultérieures, cette méthode renvoie des tailles fractionnaires (dans le composant de taille du CGRect renvoyé); pour utiliser une taille renvoyée dans les vues de taille, vous devez utiliser augmenter sa valeur à l'entier supérieur le plus proche en utilisant la fonction ceil.ceilf
, il est recommandé d'utiliser la fonction.
CGFloat height = ceilf(labelBounds.size.height);
Je crois que la fonction était obsolète parce que cette série de fonctions NSString + UIKit était basée sur la bibliothèque UIStringDrawing, qui n'était pas sûre pour les threads. Si vous avez essayé de les exécuter non pas sur le thread principal (comme toute autre fonctionnalité UIKit), vous obtiendrez des comportements imprévisibles. En particulier, si vous exécutez la fonction sur plusieurs threads simultanément, cela bloquera probablement votre application. C'est pourquoi dans iOS 6, ils ont introduit la méthode boundingRectWithSize:...
Pour NSAttributedStrings. Cela a été construit au-dessus des 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 preniez en charge que iOS 6 et iOS 7, je changerais certainement tous les sizeWithFont:...
De votre NSString en boundingRectWithSize
de NSAttributeString. Cela vous évitera beaucoup de maux de tête si vous avez un étui d'angle multi-threading étrange! Voici comment j'ai converti le sizeWithFont:constrainedToSize:
De NSString:
Ce qui était autrefois:
NSString *text = ...;
CGFloat width = ...;
UIFont *font = ...;
CGSize size = [text sizeWithFont:font
constrainedToSize:CGSizeMake(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:CGSizeMake(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 renvoie des tailles fractionnaires (dans le composant de taille du CGRect renvoyé); pour utiliser une taille renvoyée à des vues de taille, vous devez utiliser augmenter sa valeur à l'entier supérieur le plus proche à l'aide de la fonction ceil.
Donc, pour extraire la hauteur ou la largeur calculée à utiliser pour dimensionner les vues, j'utiliserais:
CGFloat height = ceilf(size.height);
CGFloat width = ceilf(size.width);
Pour les problèmes de saut de ligne:
- (CGFloat)heightNeededForText:(NSString *)text withFont:(UIFont *)font width:(CGFloat)width lineBreakMode:(NSLineBreakMode)lineBreakMode {
NSMutableParagraphStyle * paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineBreakMode = lineBreakMode;
CGSize size = [text boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX)
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
attributes:@{ NSFontAttributeName: font, NSParagraphStyleAttributeName: paragraphStyle }
context:nil].size;
return ceilf(size.height);
}
Version rapide de la réponse d'Alexandre de Norvège ...
func heightNeededForText(text: NSString, withFont font: UIFont, width: CGFloat, lineBreakMode:NSLineBreakMode) -> CGFloat {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineBreakMode = lineBreakMode
let size: CGSize = text.boundingRectWithSize(CGSizeMake(width, CGFloat.max), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: [ NSFontAttributeName: font, NSParagraphStyleAttributeName: paragraphStyle], context: nil).size//text boundingRectWithSize:CGSizeMake(width, CGFLOAT_MA
return ceil(size.height);
}
Dans le code où vous voulez obtenir la hauteur, appelez simplement la méthode comme ci-dessous ...
let size = self.heightNeededForText(text as NSString, withFont: UIFont.systemFontOfSize(15.0), width: scrollView.frame.size.width - 20, lineBreakMode: NSLineBreakMode.ByWordWrapping) //Can edit the font size and LinebreakMode