In iOS 7, sizeWithFont:
ora è obsoleto. Come posso ora passare l'oggetto UIFont nel metodo di sostituzione sizeWithAttributes:
?
In iOS 7, sizeWithFont:
ora è obsoleto. Come posso ora passare l'oggetto UIFont nel metodo di sostituzione sizeWithAttributes:
?
Risposte:
Usa sizeWithAttributes:
invece, che ora richiede un NSDictionary
. Passa la coppia con chiave UITextAttributeFont
e il tuo oggetto font in questo modo:
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:
invece usare , passando CGSizeMake(250.0f, CGFLOAT_MAX)
nella maggior parte dei casi.
Credo che la funzione sia stata deprecata perché quella serie di NSString+UIKit
funzioni ( sizewithFont:...
, ecc.) Erano basate sulla UIStringDrawing
libreria, che non era thread-safe. Se hai provato a eseguirli non sul thread principale (come qualsiasi altra UIKit
funzionalità), otterrai comportamenti imprevedibili. In particolare, se hai eseguito la funzione su più thread contemporaneamente, probabilmente si bloccherà la tua app. Questo è il motivo per cui in iOS 6, hanno introdotto un boundingRectWithSize:...
metodo per NSAttributedString
. Questo è stato creato in cima alle NSStringDrawing
librerie ed è thread-safe.
Se osservi la nuova NSString
boundingRectWithSize:...
funzione, richiede una matrice di attributi allo stesso modo di a NSAttributeString
. Se dovessi indovinare, questa nuova NSString
funzione in iOS 7 è semplicemente un wrapper per la NSAttributeString
funzione di iOS 6.
In quella nota, se tu supportassi solo iOS 6 e iOS 7, cambierei sicuramente tutti i tuoi NSString
sizeWithFont:...
in NSAttributeString
boundingRectWithSize
. Ti farà risparmiare un sacco di mal di testa se ti capita di avere una strana custodia ad angolo multi-threading! Ecco come mi sono convertito NSString
sizeWithFont:constrainedToSize:
:
Quello che era:
NSString *text = ...;
CGFloat width = ...;
UIFont *font = ...;
CGSize size = [text sizeWithFont:font
constrainedToSize:(CGSize){width, CGFLOAT_MAX}];
Può essere sostituito con:
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;
Si prega di notare che la documentazione menziona:
In iOS 7 e versioni successive, questo metodo restituisce dimensioni frazionarie (nel componente dimensioni del reso
CGRect
); per utilizzare una dimensione restituita per visualizzare le dimensioni, è necessario utilizzare aumentare il valore all'intero superiore più vicino utilizzando la funzione ceil.
Quindi, per estrarre l'altezza o la larghezza calcolata da utilizzare per il dimensionamento delle viste, utilizzerei:
CGFloat height = ceilf(size.height);
CGFloat width = ceilf(size.width);
Come puoi vedere sizeWithFont
sul sito degli sviluppatori Apple, è obsoleto, quindi è necessario utilizzarlo 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:]
il metodo come qui: stackoverflow.com/a/3863039/1226304
Ho creato una categoria per gestire questo problema, eccolo qui:
#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]);
}
In questo modo si ha solo per trovare / sostituire sizeWithFont:
con sizeWithMyFont:
e si sta bene ad andare.
In iOS7 avevo bisogno della logica per restituire l'altezza corretta per il metodo tableview: heightForRowAtIndexPath, ma sizeWithAttributes restituisce sempre la stessa altezza indipendentemente dalla lunghezza della stringa perché non sa che verrà inserita in una cella di tabella a larghezza fissa . Ho trovato che funziona alla grande per me e calcola l'altezza corretta tenendo conto della larghezza della cella della tabella! Questo si basa sulla risposta di Mr. T sopra.
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
Le etichette multilinea che utilizzano l'altezza dinamica potrebbero richiedere ulteriori informazioni per impostare correttamente le dimensioni. È possibile utilizzare sizeWithAttributes con UIFont e NSParagraphStyle per specificare sia il carattere che la modalità di interruzione di riga.
Definiresti lo stile di paragrafo e utilizzeresti un NSDictionary come questo:
// 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];
Puoi usare CGSize 'adjustedSize' o CGRect come proprietà rect.size.height se stai cercando l'altezza.
Maggiori informazioni su NSParagraphStyle qui: 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));
Creare una funzione che accetta un'istanza di UILabel. e restituisce 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;
tableView.estimatedRowHeight = 68.0 tableView.rowHeight = UITableViewAutomaticDimension
Soluzione 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];
}
Basato su @bitsand, questo è un nuovo metodo che ho appena aggiunto alla mia categoria 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;
}
Uso solo le dimensioni del frame risultante.
Puoi ancora usare sizeWithFont
. ma, in iOS> = 7.0 il metodo causa l'arresto anomalo se la stringa contiene spazi iniziali o finali o linee finali \n
.
Ritagliare il testo prima di usarlo
label.text = [label.text stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
Questo può anche valere per sizeWithAttributes
e[label sizeToFit]
.
inoltre, ogni volta che hai nsstringdrawingtextstorage message sent to deallocated instance
nel dispositivo iOS 7.0 si occupa di questo.
Meglio usare le dimensioni automatiche (Swift):
tableView.estimatedRowHeight = 68.0
tableView.rowHeight = UITableViewAutomaticDimension
NB: 1. Il prototipo UITableViewCell deve essere progettato correttamente (per l'istanza non dimenticare di impostare UILabel.numberOfLines = 0 ecc.) 2. Rimuovere il metodo HeightForRowAtIndexPath
VIDEO: https://youtu.be/Sz3XfCsSb6k
La risposta accettata in Xamarin sarebbe (usa sizeWithAttributes e UITextAttributeFont):
UIStringAttributes attributes = new UIStringAttributes
{
Font = UIFont.SystemFontOfSize(17)
};
var size = text.GetSizeUsingAttributes(attributes);
Come la risposta di @Ayush:
Come puoi vedere
sizeWithFont
sul sito degli sviluppatori Apple, è obsoleto, quindi è necessario utilizzarlosizeWithAttributes
.
Bene, supponendo che nel 2019+ probabilmente stai usando Swift e String
invece di Objective-c e NSString
, ecco il modo corretto di ottenere la dimensione di un String
carattere predefinito:
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]);
}
Ecco l'equivalente monotouch se qualcuno ne ha bisogno:
/// <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;
}
che può essere usato in questo modo:
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;
Prova questa sintassi:
NSAttributedString *attributedText =
[[NSAttributedString alloc] initWithString:text
attributes:@{NSFontAttributeName: font}];
Niente di tutto ciò ha funzionato per me in iOS 7. Ecco cosa ho finito per fare. L'ho inserito nella mia classe di cella personalizzata e chiamo il metodo nel mio metodo heightForCellAtIndexPath.
La mia cella è simile alla cella della descrizione quando si visualizza un'app nell'app store.
Per prima cosa nello storyboard, imposta l'etichetta su 'AttribText', imposta il numero di righe su 0 (che ridimensionerà automaticamente l'etichetta (solo iOS 6+)) e impostalo sul ritorno a capo automatico.
Quindi aggiungo solo tutte le altezze del contenuto della cella nella mia classe cellulare personalizzata. Nel mio caso ho un'etichetta nella parte superiore che dice sempre "Descrizione" (_descriptionHeadingLabel), un'etichetta più piccola di dimensioni variabili che contiene la descrizione effettiva (_descriptionLabel) un vincolo dalla parte superiore della cella all'intestazione (_descriptionHeadingLabelTopConstraint) . Ho anche aggiunto 3 per distanziare un po 'la parte inferiore (circa la stessa quantità di posti di mela nella cella del tipo di sottotitolo).
- (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;
}
E nel mio delegato di Table View:
- (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;
}
È possibile modificare l'istruzione if in modo che sia un po 'più "intelligente" e in realtà ottenere l'identificatore di cella da una sorta di origine dati. Nel mio caso, le celle saranno codificate in modo rigido poiché ci sarà una quantità fissa di esse in un ordine specifico.
boundingRectWithSize
in iOS 9.2 problemi attuali, sono risultati diversi da iOS <9.2. Hai trovato o conosci qualsiasi altro modo migliore per farlo.
NSString
e unUILabel
(non SEMPRE il caso, ma spesso così), per evitare duplicati di codice / ecc., è anche possibile sostituirlo[UIFont systemFontOfSize:17.0f]
conlabel.font
- aiuta la manutenzione del codice facendo riferimento a dati esistenti anziché digitandoli più volte o facendo riferimento a costanti in tutto il posto, ecc.