2013-08-19 15 views
26

ho un metodo che mi dà la dimensione ideale per un'UITextView data una lunghezza di corda (con la dimensione corrispondente carattere corretto):Con cosa dovrei sostituire il sizeWithFont: metodo deprecato?

- (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; 
} 

Infatti, ancora mi dà una misura perfetta, anche in iOS7 . Anche se ora viene fornito un metodo di avviso che dice che non dovrei usare "sizeWithFont: contrainedToSize: lineBreakMode".

E ora dice dovrei usare -boundingRectWithSize: opzioni: attributi: contesto:

Questo metodo non è nuovo a iOS7 e quindi immagino che sia giusto chiedere che in caso di overflow dello stack, piuttosto che andare attraverso il forum ufficiale degli sviluppatori di apple.

Ho tre domande:

1) Perché è deprecato, significa che dovrei sicuramente sostituirlo, nonostante ancora lavorando?

2) Ho provato molti diversi limitiRectWithSize: metodi, con varie variabili ma non è mai perfetto, sembra sempre leggermente fuori (come fanno notare molte domande StackOverflow) - C'è un sostituto perfetto con questo nessuno-deprecato metodo che fa esattamente lo stesso del mio precedente metodo con il minimo dispiacere?

3) perché rimuovere questo metodo? È a causa della sovrapposizione con questo altro metodo?

+0

Suggerire questo [link] (http://www.cnblogs.com/lisa090818/p/3445161.html). – yazh

+1

wtf è quel collegamento? – Rambatino

risposta

57

Dopo un'ora di errore di prova sono riuscito a farlo funzionare:

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

Aggiornamento:

come Mr. T cita nella risposta qui sotto: In iOS 7 e versioni successive, questo metodo restituisce dimensioni frazionarie (nel componente di dimensione del CGRect restituito); per utilizzare una vista restituita in dimensioni, è necessario utilizzare il suo valore al numero intero più vicino più vicino utilizzando la funzione ceil.ceilf si consiglia di utilizzare la funzione.

CGFloat height = ceilf(labelBounds.size.height); 
+1

Grazie per questo. Ora sto usando qualcosa di simile per iOS6, che crea una NSAttributedString usando il dizionario stringAttributes che crei e chiamo boundingRectWithSize: options: context: sulla stringa attribuita. – AidenMontgomery

+0

Grazie! Davvero utile! – Andres

13

credo che la funzione è stata sostituita perché quella serie di funzioni NSString + UIKit erano basati sulla libreria UIStringDrawing, che non è stato thread-safe. Se provi a eseguirli non sul thread principale (come qualsiasi altra funzionalità di UIKit), otterrai comportamenti imprevedibili. In particolare, se hai eseguito la funzione su più thread contemporaneamente, probabilmente causerà il crash della tua app. Questo è il motivo per cui in iOS 6 è stato introdotto il metodo boundingRectWithSize:... per NSAttributedStrings. Questo è stato costruito in cima alle librerie NSStringDrawing ed è thread-safe.

Se si osserva la nuova funzione NSString boundingRectWithSize:..., richiede una matrice di attributi nello stesso modo di NSAttributeString. Se dovessi indovinare, questa nuova funzione NSString in iOS 7 è semplicemente un wrapper per la funzione NSAttributeString da iOS 6.

In questa nota, se tu avessi solo iOS 6 e iOS 7, avrei sicuramente cambiato tutto del numero sizeWithFont:... di NSString a boundingRectWithSize di NSAttributeString. Ti farà risparmiare un sacco di mal di testa se ti capita di avere uno strano caso angolare multi-threading!Ecco come ho convertito di NSString sizeWithFont:constrainedToSize::

Che usato per essere:

NSString *text = ...; 
CGFloat width = ...; 
UIFont *font = ...; 
CGSize size = [text sizeWithFont:font 
       constrainedToSize:CGSizeMake(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:CGSizeMake(width, CGFLOAT_MAX) 
              options:NSStringDrawingUsesLineFragmentOrigin 
              context:nil]; 
CGSize size = rect.size; 

Si prega di notare la documentazione menzioni:

In iOS 7 e più tardi, questo metodo restituisce dimensioni frazionarie (nella dimensione componente del CGRect restituito); per utilizzare una dimensione restituita alle dimensioni visualizzazioni, è necessario utilizzare il valore aumentato al numero intero più vicino più vicino utilizzando la funzione ceil.

Quindi, per tirare fuori l'altezza calcolata o larghezza da utilizzare per il dimensionamento di vista, vorrei utilizzare:

CGFloat height = ceilf(size.height); 
CGFloat width = ceilf(size.width); 
+4

non risolve il problema linebreakmode – Firdous

+0

Vedere la mia risposta qui sotto. –

5

Per numero di riga:

- (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); 
} 
2

versione Swift della Risposta di Alessandro di Norvegia ...

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); 
    } 

Nel codice in cui si desidera ottenere l'altezza basta chiamare il metodo come qui di seguito ...

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 
Problemi correlati