Как переместить курсор в UITextField после установки его значения

Кто-нибудь может мне помочь с этим: мне нужно реализовать UITextField для ввода номера. Это число всегда должно быть в десятичном формате с 4 знаками, например 12,3456 или 12,3400. Итак, я создал NSNumberFormatter это помогает мне с десятичными разрядами.

Я устанавливаю UITextField значение в

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string метод. Я обрабатываю ввод, использую средство форматирования и, наконец, вызываю [textField setText: myFormattedValue];

Это работает нормально, но этот вызов также перемещает курсор в конец моего поля. Это нежелательно. Например, у меня в поле 12,3400, и курсор находится в самом начале, а пользователь вводит номер 1. Значение результата равно 112,3400, но курсор перемещается в конце. Я хочу закончить курсором, когда пользователь ожидает (сразу после недавно добавленного числа 1). Есть несколько тем о настройке курсора в TextView но это UITextField, Я тоже пытался поймать selectedTextRange поля, которое правильно сохраняет положение курсора, но после setText вызов метода, это автоматически меняет и источник UITextRange потерян (изменен на текущий). надеюсь, мое объяснение понятно.

Пожалуйста, помогите мне с этим. большое спасибо вам.

РЕДАКТИРОВАТЬ: Наконец, я решил переключить функциональность на изменение формата после всего редактирования и работает достаточно хорошо. Я сделал это, добавив селектор forControlEvents:UIControlEventEditingDidEnd,

5 ответов

После UITextField.text свойство изменено, любые предыдущие ссылки на UITextPosition или же UITextRange объекты, которые были связаны со старым текстом, будут установлены в ноль после того, как вы установите свойство текста. Вам необходимо сохранить то, каким будет смещение текста после того, как манипуляция будет ПЕРЕД тем, как вы установите свойство текста.

Это сработало для меня (обратите внимание, вам нужно проверить, является ли cursorOffset

- (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;
}

То, что на самом деле работало для меня, было очень просто, просто использовал основной асинхронный диспетчер:

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

А вот и быстрая версия:

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 версия

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

Реализуйте код, описанный в этом ответе: перемещение курсора в начало UITextField

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

РЕДАКТИРОВАТЬ: Из этого ответа, похоже, вы можете просто использовать этот код с UITextField, если вы используете iOS 5 или выше. В противном случае вам нужно вместо этого использовать UITextView.

Swift X. Для предотвращения перемещения курсора с последней позиции.

func textFieldDidChangeSelection(_ textField: UITextField) {
    let point = CGPoint(x: bounds.maxX, y: bounds.height / 2)
    if let textPosition = textField.closestPosition(to: point) {
        textField.selectedTextRange = textField.textRange(from: textPosition, to: textPosition)
    }
}
Другие вопросы по тегам