2014-10-09 17 views
18

sto cercando di applicare NSAttributedString stili per un UITextField dopo l'elaborazione di una nuova voce di testo, battitura dalla battitura. Il problema è che ogni volta che sostituisco il testo il cursore salterà proprio alla fine di ogni cambiamento. Ecco il mio approccio attuale ...Formattare il testo UITextField senza dover spostare il cursore alla fine

ricezione e cambio testo visualizzato immediatamente (stesso problema vale anche quando return false e fare la sostituzione del testo manualmente)

func textField(textField: UITextField!, shouldChangeCharactersInRange range: NSRange, replacementString string: String!) -> Bool {   
    let range:NSRange = NSRange(location: range.location, length: range.length) 
    let newString = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string); 
    return true 
} 

Mi sono iscritto alla notifica UITextFieldTextDidChangeNotification. Questo innesca lo stile. Quando il testo viene modificato, lo sostituisco (NSString) con la versione formattata (NSAttributedString) utilizzando una funzione di formattazione().

func textFieldTextDidChangeNotification(userInfo:NSDictionary) { 
    var attributedString:NSMutableAttributedString = NSMutableAttributedString(string: fullString) 
    attributedString = format(textField.text) as NSMutableAttributedString 
    textField.attributedText = attributedString 
} 

Lo styling funziona così. Tuttavia, dopo ogni sostituzione del testo, il cursore salta alla fine della stringa. Come posso disattivare questo comportamento o spostare manualmente il cursore indietro dove ha iniziato la modifica? ... o c'è una soluzione migliore per modellare il testo durante la modifica?

risposta

31

Il modo per farlo funzionare è prendere la posizione del cursore, aggiornare il contenuto del campo e quindi sostituire il cursore nella sua posizione originale. Non sono sicuro dell'esatto equivalente in Swift, ma quanto segue è come lo farei in Obj-C.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string 
{ 
    UITextPosition *beginning = textField.beginningOfDocument; 
    UITextPosition *cursorLocation = [textField positionFromPosition:beginning offset:(range.location + string.length)]; 

    textField.text = [textField.text stringByReplacingCharactersInRange:range withString:string]; 

    /* MAKE YOUR CHANGES TO THE FIELD CONTENTS AS NEEDED HERE */ 

    // cursorLocation will be (null) if you're inputting text at the end of the string 
    // if already at the end, no need to change location as it will default to end anyway 
    if(cursorLocation) 
    { 
     // set start/end location to same spot so that nothing is highlighted 
     [textField setSelectedTextRange:[textField textRangeFromPosition:cursorLocation toPosition:cursorLocation]]; 
    } 

    return NO; 
} 
+0

Oh, perfetto. Funziona così. Grazie – Bernd

8

Questa è una vecchia questione, ma ho avuto un problema simile e si sono risolti con il seguente Swift:

// store the current cursor position as a range 
var preAttributedRange: NSRange = textField.selectedRange 
// apply attributed string 
var attributedString:NSMutableAttributedString = NSMutableAttributedString(string: fullString) 
attributedString = format(textField.text) as NSMutableAttributedString 
textField.attributedText = attributedString 
// reapply the range 
textField.selectedRange = preAttributedRange 

Funziona nel contesto della mia app, speriamo che sia utile per qualcuno!

+0

questo funziona a meraviglia, grazie mille, perché la soluzione contrassegnata sopra non funzionava per me in alcuni casi. – jpincheira

2

Questo è un codice che funziona per swift 2. Buon divertimento!

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { 
    let beginnig: UITextPosition = textField.beginningOfDocument 

    if let txt = textField.text { 
     textField.text = NSString(string: txt).stringByReplacingCharactersInRange(range, withString: string) 
    } 

    if let cursorLocation: UITextPosition = textField.positionFromPosition(beginnig, offset: (range.location + string.characters.count)) { 
     textField.selectedTextRange = textField.textRangeFromPosition(cursorLocation, toPosition: cursorLocation) 
    } 

    return false 
} 

Nota che l'ultimo "se lasciato" deve sempre rimanere alla fine del codice.

+0

È 'UITextPosition * cursorLocation = [textField positionFromPosition: inizio offset: (range.location + string.length)];' non serve più? – Daniel

7

Grazie a @ Stonz2 dal codice in Objective-C. Esso funziona magicamente! L'ho usato nel mio progetto Swift. Lo stesso codice in Swift:

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { 

    let positionOriginal = textField.beginningOfDocument 
    let cursorLocation = textField.positionFromPosition(positionOriginal, offset: (range.location + NSString(string: string).length)) 

    /* MAKE YOUR CHANGES TO THE FIELD CONTENTS AS NEEDED HERE */ 

    if(cursorLocation != nil) { 
     textField.selectedTextRange = textField.textRangeFromPosition(cursorLocation!, toPosition: cursorLocation!) 
    } 
    return false 
} 
+1

Nel mio caso avevo bisogno di questo pezzo di codice in textView: ShouldChangeTextInRange, ho solo sostituito "textField" -> "textView" e "string" -> "text" e ha funzionato fuori dalla scatola. Grazie! – Vitalii