it-swarm.com.ru

Форматировать текст UITextField без перемещения курсора в конец

Я пытаюсь применить NSAttributedString styles к UITextField после обработки новой текстовой записи, нажатия клавиши по нажатию клавиши. Проблема в том, что каждый раз, когда я заменяю текст, курсор будет перескакивать в самый конец при каждом изменении. Вот мой нынешний подход ...

Получите и отобразите изменение текста немедленно (та же проблема применима, когда я возвращаю false и выполняю замену текста вручную)

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
}

Я подписался на уведомление UITextFieldTextDidChangeNotification. Это запускает стиль. Когда текст изменяется, я заменяю его ( NSString ) форматированной версией ( NSAttributedString ), используя некоторую функцию format ().

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

Укладка отлично работает, как это. Однако после каждой замены текста курсор переходит к концу строки. Как я могу отключить это поведение или вручную переместить курсор назад, где он начал редактирование? ... или есть лучшее решение для стиля текста при редактировании?

21
Bernd

Способ сделать эту работу состоит в том, чтобы захватить местоположение курсора, обновить содержимое поля, а затем заменить курсор в исходное положение. Я не уверен в точном эквиваленте в Swift, но вот как я это сделаю в 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;
}
36
Stonz2

Спасибо @ Stonz2 по коду в Objective-C. Отлично работает! Я использовал это в своем проекте Swift. Тот же код в 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 
}
9
pcsantana

Это старый вопрос, но у меня была похожая проблема, и я решил ее с помощью следующего 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

Это работает в контексте моего приложения, надеюсь, это будет полезно для кого-то!

9
jolyonruss

Этот код работает для Swift 2. Наслаждайтесь! 

 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
}

Обратите внимание, что последнее "если позволено" всегда должно оставаться в конце кода.

2
DuffMck

Чтобы дополнить другие правильные ответы в этой теме, здесь приведены некоторые фрагменты кода для Swift 4.2 и для обоих UITextField и UITextView

UITextField

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    // Update Cursor
    let positionOriginal = textField.beginningOfDocument
    let cursorLocation = textField.position(from: positionOriginal, offset: (range.location + string.count))
    if let cursorLocation = cursorLocation {
        textField.selectedTextRange = textField.textRange(from: cursorLocation, to: cursorLocation)
    }
    return false
}

UITextView

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    // Update Cursor
    let positionOriginal = textView.beginningOfDocument
    let cursorLocation = textView.position(from: positionOriginal, offset: (range.location + text.count))
    if let cursorLocation = cursorLocation {
        textView.selectedTextRange = textView.textRange(from: cursorLocation, to: cursorLocation)
    }
    return false
}
0
anders