2010-02-17 12 views
43

Voglio fare un disegno di NSAttributoString in caselle a larghezza fissa, ma sto avendo problemi a calcolare l'altezza giusta che occuperanno quando si disegna. Finora, ho provato:Come ottenere altezza per NSAttributoString a una larghezza fissa

  1. Calling - (NSSize) size, ma i risultati sono inutili (per questo scopo), come vi daranno tutto quello larghezza i desideri di stringa.

  2. Chiamando - (void)drawWithRect:(NSRect)rect options:(NSStringDrawingOptions)options con un rettangolo a forma di larghezza che voglio e NSStringDrawingUsesLineFragmentOrigin nelle opzioni, esattamente come sto usando nel mio disegno. I risultati sono ... difficili da capire; certamente non quello che sto cercando. (Come indicato in alcuni punti, tra cui this thread Cocoa-Dev).

  3. Creazione di un NSTextView temporanea e fare:
    [[tmpView textStorage] setAttributedString:aString];
    [tmpView setHorizontallyResizable:NO];
    [tmpView sizeToFit];

    Quando interrogo la cornice del tmpView, la larghezza è ancora, se lo desideri, e l'altezza è spesso corretta ... fino a arrivare a stringhe più lunghe, quando è spesso la metà delle dimensioni richieste. (Non sembra essere stata colpita una dimensione massima: un frame sarà alto 273.0 (circa 300 troppo corto), l'altro sarà 478.0 (solo 60-ish troppo corto)).

Apprezzerei qualsiasi suggerimento, se qualcun altro ha gestito questo.

risposta

15

La risposta è utilizzare
- (void)drawWithRect:(NSRect)rect options:(NSStringDrawingOptions)options
ma il rect si passa dovrebbero avere 0.0 nella dimensione che si desidera essere illimitata (che, ehm, ha perfettamente senso). Esempio here.

+2

Questa risposta è obsoleta. [La risposta di Graham] (http://stackoverflow.com/a/2460091/39155) di seguito è il metodo corretto a partire dal 2014. –

6

Potresti essere interessato alla grande categoria di Jerry Krinock (solo OS X) NS(Attributed)String+Geometrics, progettata per eseguire ogni tipo di misurazione delle stringhe, incluso quello che stai cercando.

+1

Tale codice sembra essere specifico per Mac. Non aiuterà lo sviluppo di iOS. – Brennan

+3

Hai ragione, la domanda riguardava 'NSTextView', che è una classe Mac. Non sono nemmeno sicuro che iOS abbia avuto 'NSAttributedString' quando ho risposto a questa domanda. –

+1

Ultimo input, ma solo un problema: ho avuto problemi con NS (Attribuito) String + Geometrics che sottostima costantemente l'altezza richiesta dalle stringhe lunghe. Fino ad ora, in realtà ho appena superato il risultato aggiungendo un ulteriore 25%. Ora sto cercando una soluzione nuova e migliore. Non credo che NS (Attributo) String + Geometrics funzioni bene su 10.9, 10.10 e 10.11. – Bryan

31
-[NSAttributedString boundingRectWithSize:options:] 

È possibile specificare NSStringDrawingUsesDeviceMetrics per ottenere union of all glyph bounds.

A differenza di -[NSAttributedString size], il numero restituito NSRect rappresenta le dimensioni dell'area che cambierebbe se la stringa è disegnata.

Come commenti @Bryan, boundingRectWithSize:options: è deprecato (non consigliato) in OS X 10.11 e versioni successive. Questo perché lo stile delle stringhe è ora dinamico a seconda del contesto.

Per OS X 10.11 e versioni successive, consultare la documentazione dello sviluppatore Apple Calculating Text Height.

+0

Sembra che se usi 'NSStringDrawingUsesDeviceMetrics' e non ci siano glifi che restituiscano' 0'. C'è un modo per gestire entrambe le situazioni? O devi sapere come o sapere se hai aggiunto un glifo? (Testato su iOS 8.) – zekel

+0

È logico che una stringa senza contenuto visibile restituisca un rect di dimensioni zero. Stai vedendo un nuovo comportamento su iOS 8 rispetto a iOS 7? –

+0

Intendevo dire che se hai un 'NSAttributedString' con testo (e senza glifi) e usi' NSStringDrawingUsesDeviceMetrics' la dimensione è 'CGSizeZero'. Quindi sembra che tu debba sapere se ci sono glifi prima di decidere come ottenere la dimensione ... – zekel

2

metodo Utilizzo NSAttributedString

- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options context:(NSStringDrawingContext *)context 

La dimensione è il vincolo sulla zona, la larghezza dell'area calcolata è limitato alla larghezza specificata mentre l'altezza è flessibile in base a questa larghezza. Si può specificare nil per il contesto se questo non è disponibile. Per ottenere dimensioni del testo su più righe, utilizzare NSStringDrawingUsesLineFragmentOrigin per le opzioni.

1

Ho appena sprecato un po 'di tempo su questo, quindi sto fornendo una risposta aggiuntiva per salvare gli altri in futuro.La risposta di Graham è corretto il 90%, ma che manca un pezzo chiave:

per ottenere risultati accurati con -boundingRectWithSize:options:è necessario superare le seguenti opzioni:

NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesDeviceMetrics|NSStringDrawingUsesFontLeading` 

Se si omette il lineFragmentOrigin uno, devi riprenditi le sciocchezze; il rect restituito sarà una linea singola alta e non rispetterà affatto le dimensioni che passi nel metodo.

Perché questo è così complicato e così scarsamente documentato è oltre me. Ma ce l'hai. Passa queste opzioni e funzionerà perfettamente (almeno su OS X).

+0

Inoltre: questo presuppone che tu abbia una stringa NSA attribuita creata con un determinato font e il NSParagraphStyle che stai cercando - nel mio caso, questo è uno stile di paragrafo allineato a sinistra, a capo automatico, senza sillabazione. Non dimenticare di crearlo quando crei il tuo attributo String. – Bryan

+0

Questo metodo è obsoleto il 10.11+ e non funziona più correttamente; l'altezza restituita è troppo piccola su El Capitan. – Bryan

1

Su OS X 10.11+, il seguente metodo funziona per me (da un documento di Apple Calculating Text Height)

- (CGFloat)heightForString:(NSAttributedString *)myString atWidth:(float)myWidth 
{ 
    NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:myString]; 
    NSTextContainer *textContainer = [[NSTextContainer alloc] initWithContainerSize: 
     NSMakeSize(myWidth, FLT_MAX)]; 
    NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init]; 
    [layoutManager addTextContainer:textContainer]; 
    [textStorage addLayoutManager:layoutManager]; 
    [layoutManager glyphRangeForTextContainer:textContainer]; 
    return [layoutManager 
     usedRectForTextContainer:textContainer].size.height; 
} 
0

Non una sola risposta in questa pagina ha lavorato per me, né che l'antica vecchio codice Objective-C da Apple's documentation. Quello che ho finalmente avuto la possibilità di lavorare per un UITextView viene prima impostando la proprietà text o attributedText su di esso e poi calcolare la dimensione necessaria in questo modo:

let size = textView.sizeThatFits(CGSize(width: maxWidth, height: CGFloat.max)) 

funziona perfettamente. Bello!

1

Swift 3:

let attributedStringToMeasure = NSAttributedString(string: textView.text, attributes: [ 
     NSFontAttributeName: UIFont(name: "GothamPro-Light", size: 15)!, 
     NSForegroundColorAttributeName: ClickUpConstants.defaultBlackColor 
]) 

let placeholderTextView = UITextView(frame: CGRect(x: 0, y: 0, width: widthOfActualTextView, height: 10)) 
placeholderTextView.attributedText = attributedStringToMeasure 
let size: CGSize = placeholderTextView.sizeThatFits(CGSize(width: widthOfActualTextView, height: CGFloat.greatestFiniteMagnitude)) 

height = size.height 

Questa risposta funziona grande per me, a differenza degli altri quelli che mi stavano dando altezze non corretti per le stringhe più grandi.

Se si vuole fare questo con testo normale al posto del testo attribuito, effettuare le seguenti operazioni:

let placeholderTextView = UITextView(frame: CGRect(x: 0, y: 0, width: ClickUpConstants.screenWidth - 30.0, height: 10)) 
placeholderTextView.text = "Some text" 
let size: CGSize = placeholderTextView.sizeThatFits(CGSize(width: widthOfActualTextView, height: CGFloat.greatestFiniteMagnitude)) 

height = size.height 
0

come un sacco di ragazzi di cui sopra, e la base sulla mia prova.

Io uso open func boundingRect(with size: CGSize, options: NSStringDrawingOptions = [], context: NSStringDrawingContext?) -> CGRect su iOS come questo sotto:

let rect = attributedTitle.boundingRect(with: CGSize(width:200, height:0), options: NSStringDrawingOptions.usesLineFragmentOrigin, context: nil) 

Qui il 200 è la larghezza fissa come previsto, altezza ho dargli 0 in quanto penso che sia meglio dire tipo altezza API è illimitato.

L'opzione non è così importante qui, ho provato .usesLineFragmentOrigin o .usesLineFragmentOrigin.union(.usesFontLeading) o .usesLineFragmentOrigin.union(.usesFontLeading).union(.usesDeviceMetrics), dà lo stesso risultato.

E il risultato è come previsto.

Grazie.

2

Ho una stringa attribuita complessa con più caratteri e ho ottenuto risultati errati con alcune delle risposte di cui sopra che ho provato prima. L'utilizzo di un UITextView mi ha dato l'altezza corretta, ma era troppo lento per il mio caso d'uso (dimensionando le celle di raccolta). Ho scritto codice rapido usando lo stesso approccio generale descritto nello Apple doc referenziato in precedenza e descritto da Erik. Questo mi ha dato risultati corretti con un'esecuzione più veloce di un UITextView fare il calcolo.

private func heightForString(_ str : NSAttributedString, width : CGFloat) -> CGFloat { 
    let ts = NSTextStorage(attributedString: str) 

    let size = CGSize(width:width, height:CGFloat.greatestFiniteMagnitude) 

    let tc = NSTextContainer(size: size) 
    tc.lineFragmentPadding = 0.0 

    let lm = NSLayoutManager() 
    lm.addTextContainer(tc) 

    ts.addLayoutManager(lm) 
    lm.glyphRange(forBoundingRect: CGRect(origin:CGPoint(x:0,y:0),size:size), in: tc) 

    let rect = lm.usedRect(for: tc) 
    return rect.size.height 
} 
+0

ha funzionato come un fascino – Harish