2013-09-23 7 views
5

Molti dei metodi che stavo usando per determinare il layout delle stringhe stampate per la creazione di documenti PDF complessi sono stati deprecati in iOS7. Documentazione chiama lo stesso metodo da utilizzare come ricambio per tutti i metodi sizeWithFont che sono obsoleti:Sostituzione per sizeWithFont: ForWidth: lineBreakMode:

boundingRectWithSize:options:attributes: 

che è bene per sizeWithFont:ConstrainedTosize:lineBreakMode, ma cosa succede se voglio la mia stringa su una sola riga? Non so cosa usare per l'altezza massima, quindi non ho un rect da consegnare come valore per il primo parametro.

Ecco cosa ho quando si limita a una determinata dimensione.

CGFloat maxHeightAllowable = _maxHeight; 
CGSize issueTitleMaxSize = CGSizeMake(_issueListTitleColWidth - (kColumnMargin *2), maxHeightAllowable); 
NSDictionary *issueTitleAttributes = [NSDictionary dictionaryWithObjectsAndKeys:_bodyFont, NSFontAttributeName, nil]; 
CGRect issueTitleRect = CGRectIntegral([issueTitleText boundingRectWithSize:issueTitleMaxSize options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) attributes:issueTitleAttributes context:nil]); 
CGSize issueTitleSize = issueTitleRect.size; 

Come vorrei utilizzare questo stesso metodo se non so il maxHeight, o in realtà, l'altezza di una riga è esattamente quello che sto cercando di scoprire?

Capisco perché stanno spingendo verso la compatibilità per le stringhe NSA e il layout automatico ma perché deprecano questi? La sostituzione, nel mio caso, ora vogliono 4 o 5 passaggi dove è usato per essere 1 o 2.

Usando la proprietà lineHeight di carattere, come suggerito da Mr T, ho fatto questi metodi in una categoria che semplifica notevolmente la mia sostituzione.

#import "NSString+SizingForPDF.h" 

@implementation NSString (SizingForPDF) 

-(CGSize)integralSizeWithFont:(UIFont *)font constrainedToSize:(CGSize)maxSize 
{ 
    NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil]; 
    CGRect rect = CGRectIntegral([self boundingRectWithSize:maxSize options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) attributes:attributes context:nil]); 
    return rect.size; 
} 

-(CGSize)integralSizeWithFont:(UIFont *)font maxWidth:(CGFloat)maxWidth numberOfLines:(NSInteger)lines 
{ 
    if (lines == 0) { 
     lines = 1; 
    } 
    NSDictionary *attributes = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName]; 
    CGFloat height = font.lineHeight * lines; 
    CGSize maxsize = CGSizeMake(maxWidth, height); 
    CGRect rect = CGRectIntegral([self boundingRectWithSize:maxsize options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesFontLeading attributes:attributes context:nil]); 
    return rect.size; 
} 

@end 

risposta

15

Se tu fossi solo cercando l'altezza di una riga, non hai potuto utilizzare la proprietà lineHeight il vostro font? Lo uso per impostare l'altezza delle mie etichette o anticipare correttamente l'altezza degli elementi senza problemi. Non sono sicuro che i documenti PDF siano diversi a questo proposito.

Inoltre, credo che quelle funzioni fossero deprecate perché quella serie di funzioni NSString + UIKit (sizeWithFont:..., ecc.) Erano basate sulla libreria UIStringDrawing, che non era 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.

In tale nota, se si stesse supportando solo iOS 6 e iOS 7, si cambierebbe definitivamente tutti gli sizeWithFont:... di NSString in 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:(CGSize){width, CGFLOAT_MAX}]; 

può essere facilmente 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 la documentazione menzioni:

In iOS 7 e versioni successive, questo metodo restituisce le dimensioni frazionarie (nella dimensione componente del reso ed CGRect); 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); 
+0

Il tuo metodo è più o meno uguale al mio, solo io uso la macro CGRectIntegral per bloccare i valori in numeri interi. Non ho mai pensato di guardare il font per l'altezza della linea. Questa è stata la risposta per me. L'ho usato per creare un paio di nuovi metodi in una categoria che sostituisce più facilmente il mio codice precedente. –

+1

LineBreakMode è sostituito da un attributo NSParagraphStyle che può essere aggiunto al dizionario degli attributi. Vedi http://stackoverflow.com/a/26894770/338468 per un esempio dettagliato di come farlo. –