In iOS 7 sizeWithFont:
ist jetzt veraltet. Wie übergebe ich jetzt das UIFont-Objekt an die Ersetzungsmethode sizeWithAttributes:
?
In iOS 7 sizeWithFont:
ist jetzt veraltet. Wie übergebe ich jetzt das UIFont-Objekt an die Ersetzungsmethode sizeWithAttributes:
?
Antworten:
Verwenden Sie sizeWithAttributes:
stattdessen, was jetzt eine dauert NSDictionary
. Übergeben Sie das Paar mit dem Schlüssel UITextAttributeFont
und Ihrem Schriftobjekt wie folgt:
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));
boundingRectWithSize:options:attributes:context:
stattdessen verwenden und CGSizeMake(250.0f, CGFLOAT_MAX)
in den meisten Fällen übergeben.
Ich glaube, die Funktion war veraltet, weil diese Reihe von NSString+UIKit
Funktionen ( sizewithFont:...
usw.) auf der UIStringDrawing
Bibliothek basierte , die nicht threadsicher war. Wenn Sie versucht haben, sie nicht im Hauptthread auszuführen (wie bei allen anderen UIKit
Funktionen), treten unvorhersehbare Verhaltensweisen auf. Insbesondere wenn Sie die Funktion auf mehreren Threads gleichzeitig ausgeführt haben, wird Ihre App wahrscheinlich abstürzen. Aus diesem Grund haben sie in iOS 6 die boundingRectWithSize:...
Methode für eingeführt NSAttributedString
. Dies wurde auf den NSStringDrawing
Bibliotheken aufgebaut und ist threadsicher.
Wenn Sie sich die neue NSString
boundingRectWithSize:...
Funktion ansehen , werden Sie auf die gleiche Weise wie bei a nach einem Attributarray gefragt NSAttributeString
. Wenn ich raten müsste, ist diese neue NSString
Funktion in iOS 7 lediglich ein Wrapper für die NSAttributeString
Funktion von iOS 6.
In diesem Sinne, wenn Sie nur iOS 6 und iOS 7 unterstützen würden, würde ich definitiv alle Ihre NSString
sizeWithFont:...
auf ändern NSAttributeString
boundingRectWithSize
. Es erspart Ihnen viel Kopfschmerzen, wenn Sie einen seltsamen Multithreading-Eckfall haben! So habe ich konvertiert NSString
sizeWithFont:constrainedToSize:
:
Was früher war:
NSString *text = ...;
CGFloat width = ...;
UIFont *font = ...;
CGSize size = [text sizeWithFont:font
constrainedToSize:(CGSize){width, CGFLOAT_MAX}];
Kann ersetzt werden durch:
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;
Bitte beachten Sie die Dokumentation Erwähnungen:
In iOS 7 und höher gibt diese Methode gebrochene Größen zurück (in der Größenkomponente der zurückgegebenen
CGRect
). Um eine zurückgegebene Ansicht von Größe zu Größe zu verwenden, müssen Sie den Wert mithilfe der Ceil-Funktion auf die nächsthöhere Ganzzahl erhöhen.
Um die berechnete Höhe oder Breite herauszuziehen, die für die Größenanpassung von Ansichten verwendet werden soll, würde ich Folgendes verwenden:
CGFloat height = ceilf(size.height);
CGFloat width = ceilf(size.width);
Wie Sie sizeWithFont
auf der Apple Developer-Website sehen können, ist es veraltet, daher müssen wir es verwenden 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]}];
}
[NSObject respondsToSelector:]
Methode wie hier zu verwenden: stackoverflow.com/a/3863039/1226304
Ich habe eine Kategorie erstellt, um dieses Problem zu lösen. Hier ist sie:
#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]);
}
Auf diese Weise können nur finden , haben / Ersetzen sizeWithFont:
mit sizeWithMyFont:
und du bist gut zu gehen.
In iOS7 brauchte ich die Logik, um die richtige Höhe für die Tabellenansicht zurückzugeben: heightForRowAtIndexPath-Methode, aber die sizeWithAttributes geben unabhängig von der Zeichenfolgenlänge immer dieselbe Höhe zurück, da sie nicht wissen, dass sie in eine Tabellenzelle mit fester Breite eingefügt werden . Ich fand das funktioniert gut für mich und berechnet die richtige Höhe unter Berücksichtigung der Breite für die Tabellenzelle! Dies basiert auf der obigen Antwort von Herrn 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
Für mehrzeilige Beschriftungen mit dynamischer Höhe sind möglicherweise zusätzliche Informationen erforderlich, um die Größe richtig einzustellen. Sie können sizeWithAttributes mit UIFont und NSParagraphStyle verwenden, um sowohl die Schriftart als auch den Zeilenumbruchmodus anzugeben.
Sie würden den Absatzstil definieren und ein NSDictionary wie folgt verwenden:
// 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];
Sie können CGSize 'adjustedSize' oder CGRect als Eigenschaft rect.size.height verwenden, wenn Sie nach der Höhe suchen.
Weitere Informationen zu NSParagraphStyle finden Sie hier: 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));
Erstellen Sie eine Funktion, die eine UILabel-Instanz akzeptiert. und gibt CGSize zurück
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;
tableView.estimatedRowHeight = 68.0 tableView.rowHeight = UITableViewAutomaticDimension
Alternative Lösung
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];
}
Aufbauend auf @bitsand ist dies eine neue Methode, die ich gerade zu meiner Kategorie NSString + Extras hinzugefügt habe:
- (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;
}
Ich benutze nur die Größe des resultierenden Rahmens.
Sie können immer noch verwenden sizeWithFont
. In iOS> = 7.0 führt die Methode jedoch zum Absturz, wenn die Zeichenfolge führende und nachfolgende Leerzeichen oder Endzeilen enthält \n
.
Beschneiden von Text vor der Verwendung
label.text = [label.text stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
Das kann auch für sizeWithAttributes
und gelten [label sizeToFit]
.
Wenn Sie ein nsstringdrawingtextstorage message sent to deallocated instance
iOS 7.0-Gerät verwenden, wird dies ebenfalls behandelt.
Verwenden Sie besser automatische Abmessungen (Swift):
tableView.estimatedRowHeight = 68.0
tableView.rowHeight = UITableViewAutomaticDimension
NB: 1. Der UITableViewCell-Prototyp sollte ordnungsgemäß entworfen sein (für die Instanz nicht vergessen, UILabel.numberOfLines = 0 usw. zu setzen). 2. Entfernen Sie die HeightForRowAtIndexPath-Methode
VIDEO: https://youtu.be/Sz3XfCsSb6k
Akzeptierte Antwort in Xamarin wäre (benutze sizeWithAttributes und UITextAttributeFont):
UIStringAttributes attributes = new UIStringAttributes
{
Font = UIFont.SystemFontOfSize(17)
};
var size = text.GetSizeUsingAttributes(attributes);
Als @ Ayush-Antwort:
Wie Sie
sizeWithFont
auf der Apple Developer-Website sehen können, ist es veraltet, daher müssen wir es verwendensizeWithAttributes
.
Angenommen, Sie verwenden ab 2019 wahrscheinlich Swift und String
anstelle von Objective-c und erhalten NSString
auf die richtige Weise die Größe einer String
mit vordefinierter Schriftart:
let stringSize = NSString(string: label.text!).size(withAttributes: [.font : UIFont(name: "OpenSans-Regular", size: 15)!])
- (CGSize) sizeWithMyFont:(UIFont *)fontToUse
{
if ([self respondsToSelector:@selector(sizeWithAttributes:)])
{
NSDictionary* attribs = @{NSFontAttributeName:fontToUse};
return ([self sizeWithAttributes:attribs]);
}
return ([self sizeWithFont:fontToUse]);
}
Hier ist das Monotouch-Äquivalent, wenn jemand es braucht:
/// <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;
}
welches so verwendet werden kann:
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;
Versuchen Sie diese Syntax:
NSAttributedString *attributedText =
[[NSAttributedString alloc] initWithString:text
attributes:@{NSFontAttributeName: font}];
Nichts davon hat in iOS 7 für mich funktioniert. Hier ist, was ich letztendlich getan habe. Ich füge dies in meine benutzerdefinierte Zellenklasse ein und rufe die Methode in meiner heightForCellAtIndexPath-Methode auf.
Meine Zelle ähnelt der Beschreibungszelle beim Anzeigen einer App im App Store.
Setzen Sie zuerst im Storyboard Ihre Beschriftung auf "attributedText", setzen Sie die Anzahl der Zeilen auf 0 (wodurch die Größe der Beschriftung automatisch geändert wird (nur ios 6+)) und setzen Sie sie auf Zeilenumbruch.
Dann addiere ich einfach alle Höhen des Inhalts der Zelle in meiner benutzerdefinierten Zellenklasse. In meinem Fall habe ich oben eine Beschriftung mit der Aufschrift "Description" (_descriptionHeadingLabel), eine kleinere Beschriftung mit variabler Größe, die die tatsächliche Beschreibung (_descriptionLabel) enthält, eine Einschränkung vom oberen Rand der Zelle bis zur Überschrift (_descriptionHeadingLabelTopConstraint). . Ich habe auch 3 hinzugefügt, um den Boden ein wenig auszuräumen (ungefähr die gleiche Menge Apfel platziert auf der Zelle vom Untertiteltyp.)
- (CGFloat)calculateHeight
{
CGFloat width = _descriptionLabel.frame.size.width;
NSAttributedString *attributedText = _descriptionLabel.attributedText;
CGRect rect = [attributedText boundingRectWithSize:(CGSize){width, CGFLOAT_MAX} options: NSStringDrawingUsesLineFragmentOrigin context:nil];
return rect.size.height + _descriptionHeadingLabel.frame.size.height + _descriptionHeadingLabelTopConstraint.constant + 3;
}
Und in meinem Delegierten für Tabellenansicht:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
if (indexPath.row == 0) {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"descriptionCell"];
DescriptionCell *descriptionCell = (DescriptionCell *)cell;
NSString *text = [_event objectForKey:@"description"];
descriptionCell.descriptionLabel.text = text;
return [descriptionCell calculateHeight];
}
return 44.0f;
}
Sie können die if-Anweisung so ändern, dass sie etwas intelligenter ist, und die Zellenkennung tatsächlich aus einer Datenquelle abrufen. In meinem Fall werden die Zellen hartcodiert, da es eine feste Menge von ihnen in einer bestimmten Reihenfolge gibt.
boundingRectWithSize
in ios 9.2 Probleme darstellen, gibt es andere Ergebnisse als in ios <9.2. Sie haben einen anderen besten Weg gefunden oder kennen ihn, um dies zu erreichen.
NSString
und einUILabel
(nicht immer der Fall, aber oft so), duplizierten Code zu verhindern / etc, können Sie auch ersetzen[UIFont systemFontOfSize:17.0f]
mitlabel.font
- hilft Code Wartung durch Verweisen auf vorhandene Daten vs. Sie es mehrmals oder Referenzierung Konstanten alle über die Eingabe Ort, etc