web-dev-qa-db-fra.com

comment déplacer le curseur dans UITextField après avoir défini sa valeur

quelqu'un peut-il m'aider avec ceci: je dois implémenter UITextField pour le numéro d'entrée. Ce nombre doit toujours être au format décimal avec 4 positions, par exemple. 12.3456 ou 12.3400 . J'ai donc créé NSNumberFormatter qui m'aide avec les décimales.

Je mets la valeur UITextField dans

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string méthode. Je procède en entrée, utilise le formateur et enfin appelle [textField setText: myFormattedValue];

Cela fonctionne bien, mais cet appel déplace également le curseur à la fin de mon champ. C'est indésirable. Par exemple. J'ai 12.3400 dans mon champ et le curseur est situé au tout début et l'utilisateur tape le numéro 1. La valeur du résultat est 112.3400 mais le curseur est déplacé à la fin. Je veux terminer avec le curseur lorsque l'utilisateur s'y attend (juste après le nombre 1 récemment ajouté). Il y a quelques sujets sur la définition du curseur dans TextView mais c'est UITextField. J'ai également essayé d'attraper selectedTextRange du champ, ce qui enregistre correctement la position du curseur, mais après l'appel de la méthode setText, cela change automatiquement et l'origine UITextRange est perdue (remplacée par current). j'espère que mon explication est claire.

S'il vous plait, j'ai besoin de votre aide avec ceci. Merci beaucoup. 

EDIT: Finalement, j’ai décidé de passer de la fonctionnalité au changement de format après une édition complète et fonctionne assez bien. Je l'ai fait en ajoutant un sélecteur forControlEvents:UIControlEventEditingDidEnd.

26
user1135839

Une fois la propriété UITextField.text modifiée, les références précédentes aux objets UITextPosition ou UITextRange associés à l'ancien texte seront définies sur nil après la définition de la propriété text. Vous devez stocker le décalage de texte après la manipulation AVANT de définir la propriété text.

Cela a fonctionné pour moi (remarque, vous devez tester si cursorOffset est <textField.text.length si vous supprimez des caractères de t dans l'exemple ci-dessous):

- (BOOL) textField:(UITextField *) textField shouldChangeCharactersInRange:(NSRange) range replacementString:(NSString *) string

{
    UITextPosition *beginning = textField.beginningOfDocument;
    UITextPosition *start = [textField positionFromPosition:beginning offset:range.location];
    UITextPosition *end = [textField positionFromPosition:start offset:range.length];
    UITextRange *textRange = [textField textRangeFromPosition:start toPosition:end];

    // this will be the new cursor location after insert/paste/typing
    NSInteger cursorOffset = [textField offsetFromPosition:beginning toPosition:start] + string.length; 

    // now apply the text changes that were typed or pasted in to the text field
    [textField replaceRange:textRange withText:string];

    // now go modify the text in interesting ways doing our post processing of what was typed...
    NSMutableString *t = [textField.text mutableCopy];
    t = [t upperCaseString];
    // ... etc

    // now update the text field and reposition the cursor afterwards
    textField.text = t;
    UITextPosition *newCursorPosition = [textField positionFromPosition:textField.beginningOfDocument offset:cursorOffset];
    UITextRange *newSelectedRange = [textField textRangeFromPosition:newCursorPosition toPosition:newCursorPosition];
    [textField setSelectedTextRange:newSelectedRange];

    return NO;
}
41
JasonD

Voici une version de Swift 3

extension UITextField {
    func setCursor(position: Int) {
        let position = self.position(from: beginningOfDocument, offset: position)!
        selectedTextRange = textRange(from: position, to: position)
    }
}
3
Jeremy Piednoel

Et voici la version Swift: 

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    let beginning = textField.beginningOfDocument
    let start = textField.positionFromPosition(beginning, offset:range.location)
    let end = textField.positionFromPosition(start!, offset:range.length)
    let textRange = textField.textRangeFromPosition(start!, toPosition:end!)
    let cursorOffset = textField.offsetFromPosition(beginning, toPosition:start!) + string.characters.count

// just used same text, use whatever you want :)
    textField.text = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)

    let newCursorPosition = textField.positionFromPosition(textField.beginningOfDocument, offset:cursorOffset)
    let newSelectedRange = textField.textRangeFromPosition(newCursorPosition!, toPosition:newCursorPosition!)
    textField.selectedTextRange = newSelectedRange

    return false
}
3
ergunkocak

Implémentez le code décrit dans cette réponse: Déplacer le curseur au début de UITextField

NSRange beginningRange = NSMakeRange(0, 0);
NSRange currentRange = [textField selectedRange];
if(!NSEqualRanges(beginningRange, currentRange))
{
    [textField setSelectedRange:beginningRange];
}

EDIT: De cette réponse , il semble que vous pouvez simplement utiliser ce code avec votre UITextField si vous utilisez iOS 5 ou une version ultérieure. Sinon, vous devez utiliser une UITextView à la place.

2
gtmtg

Ce qui a réellement fonctionné pour moi était très simple, juste utilisé async principal de dispatch:

DispatchQueue.main.async(execute: {
  textField.selectedTextRange = textField.textRange(from: start, to: end)
})
0
Everton Cunha