Voglio calcolare i limiti minimi per un rettangolo necessario per adattare una stringa (linea multipla) con un carattere specifico.Stringa: Limiti minimi per l'altezza massima
Dovrebbe essere qualcosa di simile:
FROM:
----------------------------------
|Sent when the application is about|
|to move from active to inactive |
|state. |
----------------------------------
TO:
-------------------------
|Sent when the application|
|is about to move from |
|active to inactive state.|
-------------------------
Come si può vedere, l'altezza rimane lo stesso, i cambiamenti di larghezza al valore minimo necessario.
Inizialmente avrei potuto usare boundingRectWithSize
(vincolo alla larghezza massima) per ottenere prima l'altezza minima necessaria e quindi chiamare boundingRectWithSize
(vincolo all'altezza calcolata) ottenere la larghezza. Ma questo produce risultati errati quando si calcola la larghezza nel secondo passaggio. Non considera l'altezza massima ma calcola semplicemente la larghezza per una singola stringa di linea.
Dopo che ho trovato un modo per ottenere il risultato corretto, ma l'esecuzione di questo codice impiega davvero tanto tempo che lo rende di alcuna utilità per me:
Prima calcolare il rettangolo necessario per la larghezza vincolo:
var objectFrame = Class.sizeOfString(string, font: objectFont, width: Double(width), height: DBL_MAX)
la larghezza:
objectFrame.size.width = Class.minWidthForHeight(string, font: objectFont, objectFrame.size.height)
utilizzando:
class func minWidthForHeight(string: NSString, font: UIFont, height: CGFloat) -> CGFloat
{
let deltaWidth: CGFloat = 5.0
let neededHeight: CGFloat = rect.size.height
var testingWidth: CGFloat = rect.size.width
var done = false
while (done == false)
{
testingWidth -= deltaWidth
var newSize = Class.sizeOfString(string, font: font, width: Double(testingWidth), height: DBL_MAX)
if (newSize.height > neededHeight)
{
testingWidth += deltaWidth
done = true
}
}
return testingWidth
}
class func sizeOfString(string: NSString, font: UIFont, width: Double, height: Double) -> CGRect
{
return string.boundingRectWithSize(CGSize(width: width, height: height),
options: NSStringDrawingOptions.UsesLineFragmentOrigin,
attributes: [NSFontAttributeName: font],
context: nil)
}
Calcola gradualmente l'altezza per una determinata larghezza (- 5,0 pixel ogni nuovo passo) e verifica se l'altezza rimane uguale. Non appena l'altezza cambia, restituisce la larghezza del passaggio precedente. Quindi ora abbiamo un rettangolo di delimitazione in cui la stringa per un certo carattere si adatta perfettamente senza alcuno spazio sprecato.
Ma come ho detto, ci vuole molto tempo per calcolare, specialmente quando lo si fa per molte stringhe diverse contemporaneamente.
C'è un modo migliore e più veloce per fare questo?
Non so una soluzione su come calcolare questo con un passaggio, ma forse è possibile sostituire la ricerca lineare per la larghezza migliore con una ricerca binaria. Prendi due valori, con uno più piccolo troppo stretto e uno più largo sufficientemente largo. Controlla la larghezza a metà tra questi valori. Se è ancora buono, imposta il valore più grande sulla larghezza testata, se è troppo piccolo, regola il valore più piccolo. Ripetere. Non è O (1) ma O (log n) invece di O (n). A seconda del numero di tentativi che devi effettuare per ogni stringa, questo potrebbe già accelerare le cose. – Nero
Ovviamente ciò richiede ipotesi abbastanza intelligenti (non perfette) per i valori iniziali, in particolare quello più piccolo, che dovrebbe essere troppo piccolo. Più lungo è il testo, più questo numero può essere scelto, penso. Forse il numero più piccolo può essere impostato su '(1 - 1/numberOfLinesWithMaxWidth) * maxWidth' inizialmente. – Nero
Funziona piuttosto bene. Ci vuole ancora molto tempo per calcolare, ma quel tempo è stato significativamente ridotto. – freshking