2009-05-12 7 views
6

Ho bisogno di spostare il testo che l'utente ha inserito in una grande linea multipla UITextView in una più piccola (ma ancora multilinea) UITextView *. Se l'utente ha inserito più testo di quello che verrà visualizzato nella vista più piccola, voglio troncare il testo in modo che si adatti a tutto il testo (troncato) visibile. (Né il grande UITextView né quello più piccolo dovrebbe scorrere.)Lunghezza stringa con font specificato per adattarsi a UITextView

Qual è il modo migliore per farlo?

È possibile utilizzare un ciclo, accorciando la stringa di un carattere ogni volta, quindi utilizzare NSString's sizeWithFont: constrainedToSize: lineBreakMode: per individuare l'altezza di questa stringa più corta, quindi confrontarla con l'altezza che ho disponibile nel mio più piccolo UITextView, termina il ciclo quando la stringa si adatta - ma sembra lento e impacciato. Ci deve essere un modo migliore.

Mi piacerebbe solo dire alla destinazione UITextView di troncare il suo membro displayText mentre lo visualizza sullo schermo, ma non sono riuscito a trovare un modo per farlo.

* Altro contesto su questo, da un commento che ho fatto qui di seguito:

Ho un app paesaggio. Modifico il layout della vista in base alla foto scelta dall'utente. Se si tratta di una foto di paesaggio, la didascalia è più piccola - solo una linea nella parte inferiore della foto. Se sceglie una foto ritratto, c'è molto spazio che posso usare per la didascalia a lato della foto, quindi la didascalia è più grande.

Se l'utente modifica l'orientamento della foto da verticale a orizzontale, quindi voglio troncare il testo e quindi consentirle di modificarlo in modo che abbia senso. Potrei semplicemente farlo, ma preferirei conservarlo per minimizzare la sua digitazione.

risposta

3

Ho scritto il seguente metodo ricorsivo e l'API pubblica per farlo correttamente. Il fattore brutto fondente è oggetto di this question.

#define kFudgeFactor 15.0 
#define kMaxFieldHeight 9999.0 

// recursive method called by the main API 
-(NSString*) sizeStringToFit:(NSString*)aString min:(int)aMin max:(int)aMax 
{ 
if ((aMax-aMin) <= 1) 
    { 
    NSString* subString = [aString substringToIndex:aMin]; 
    return subString; 
    } 

int mean = (aMin + aMax)/2; 
NSString* subString = [aString substringToIndex:mean]; 

CGSize tallerSize = CGSizeMake(self.frame.size.width-kFudgeFactor,kMaxFieldHeight); 
CGSize stringSize = [subString sizeWithFont:self.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap]; 

if (stringSize.height <= self.frame.size.height) 
    return [self sizeStringToFit:aString min:mean max:aMax]; // too small 
else  
     return [self sizeStringToFit:aString min:aMin max:mean];// too big 
} 

-(NSString*)sizeStringToFit:(NSString*)aString 
{ 

CGSize tallerSize = CGSizeMake(self.frame.size.width-kFudgeFactor,kMaxFieldHeight); 
CGSize stringSize = [aString sizeWithFont:self.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap]; 

// if it fits, just return 
if (stringSize.height < self.frame.size.height) 
    return aString; 

// too big - call the recursive method to size it  
NSString* smallerString = [self sizeStringToFit:aString min:0 max:[aString length]]; 
return smallerString; 
} 
+0

questo codice è fantastico, grazie, ma ho trovato due situazioni in cui fallisce: 1) se hai un sacco di spazi sulla stringa 2) il "<" nella riga "if (stringSize.height SpaceDog

1

Suggerirei di adottare un approccio leggermente diverso e vedere se è possibile utilizzare un UILabel al posto del più piccolo UITextView.

UILabels può essere configurato per essere multi-linea come un UITextView attraverso la loro proprietà numberOfLines.

UILabels ha anche una proprietà lineBreakMode e credo che il valore predefinito di tale proprietà esegua l'effetto di troncamento esatto che si sta cercando.

+1

Ma non credo che UILabels possa essere modificabile, vero? Voglio che l'utente possa inserire il testo in entrambi questi campi. (Soprattutto una volta che l'ho troncato, probabilmente il testo non ha senso.) –

+0

Hai ragione UILabels non è modificabile. Immagino che mi abbia bloccato per ora. In generale, mi chiedo quale sarebbe l'esperienza dell'utente durante la modifica del tuo UITextView più piccolo. L'utente può modificare tutto il testo o solo la parte che non è stata troncata? Se l'utente è in grado di modificare tutto il testo, in che modo l'utente può dire che le sue modifiche hanno avuto effetto se vengono troncate una volta terminata la sessione di modifica? Per queste ragioni, potrei considerare di mantenere la vista più piccola come un riepilogo di sola lettura del testo. –

+0

Sono necessarie ulteriori informazioni. Ho un'app per il paesaggio. Quello che succede è che cambio il layout della vista a seconda della foto che l'utente sceglie. Se si tratta di una foto di paesaggio, la didascalia è più piccola - solo una linea nella parte inferiore della foto. Se scelgono una foto ritratto, c'è un sacco di spazio che posso usare per la didascalia a lato della foto, quindi la didascalia è più grande. Se l'utente cambia il suo orientamento della foto da verticale a orizzontale, quindi voglio troncare il testo e quindi permettergli di cambiarlo per avere un senso. –

1

Credo che Jonathan era a qualcosa circa l'UILabel ...

Quindi, l'utente termina la modifica del UITextView, si ottiene la stringa di testo e passare alla UILabel. Si modifica l'alfa di UITextView a 0 e/o rimuoverlo da superview. È possibile archiviare il testo completo non troncato in un ivar.

UILabels non sono "modificabili", tuttavia è possibile rilevare un tocco con una UILabel (o la sua superview). Quando si rileva il tocco su UILabel, è sufficiente ripristinare la UITextView nascosta e ripristinare la stringa salvata.

A volte l'SDK è un dolore, ma quasi sempre vince il combattimento. Molte volte, è meglio adattare il design alle convenzioni UIKit

2

Questa non è in realtà una correzione ma fornisce un buon punto di partenza per il calcolo.

Se si utilizza NSString sizeWithFont: constrainedToSize: lineBreakMode: si ottiene un'altezza verticale per il testo. Se lo dividi con l'altezza iniziale del tuo font, ottieni il numero di linee nell'intera stringa. Dividere [numero NSString] di quel numero ti dà un'approssimazione al numero di caratteri per riga.Questo presuppone la stringa è homogeneuous e sarà imprecisa se qualcuno (ad esempio)

Si può anche dividere si delimitazione Box di leading l'altezza del carattere relevent a 'iiiiiiiiiii ..." come oposed a 'MMMMMMMMM ...'. ottenere il numero di linee che si adattano all'interno della vostra casella di delimitazione.

Moltiplicando caratteri per riga per numero di linee che si dà un punto di partenza per la ricerca di testo che si adatta.

si potrebbe calcolare il margine di errore in questa cifra per facendo lo stesso calcolo per le stringhe "iiiiii ..." e "MMMMMM ..." "

+0

D'accordo, questo è un buon approccio, e quindi sta facendo un binario sulla lunghezza della stringa usando il metodo sopra. Sto ancora sperando che ci sia un modo migliore, ma ho la sensazione che ora non ci sia. –

+0

La soluzione è Courier. Font a larghezza fissa, niente matematica ... –

+0

@Tristan, solo se si ignorano gli spazi bianchi durante il wrapping. Sarebbe comunque un problema più semplice. –

Problemi correlati