UITextField с защищенным входом, всегда очищается перед редактированием - PullRequest
33 голосов
/ 05 сентября 2011

У меня странная проблема, из-за которой мой UITextField, который содержит защищенную запись, всегда очищается, когда я пытаюсь ее отредактировать. Я добавил 3 символа в поле, перешел в другое поле и вернулся, курсор находится в позиции 4-го символа, но когда я пытаюсь добавить другой символ, весь текст в поле очищается новым символом. У меня «Очистить, когда редактирование начинается» снят в перо. Так в чем же проблема? Если я удаляю свойство защищенной записи, все работает нормально, так это свойство текстовых полей защищенной записи? Есть ли способ предотвратить такое поведение?

Ответы [ 23 ]

46 голосов
/ 05 сентября 2011

комплект,

textField.clearsOnBeginEditing = NO;

Примечание. Это не будет работать, если secureTextEntry = YES . Кажется, по умолчанию iOS очищает текст текстовых полей защищенного ввода перед редактированием, независимо от того, clearsOnBeginEditing - ДА или НЕТ.

45 голосов
/ 25 октября 2013

Если вы не хотите, чтобы поле очищалось, даже если secureTextEntry = YES, используйте:

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

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

    textField.text = updatedString;

    return NO;
}

Я столкнулся с подобной проблемой при добавлении функции отображения / скрытия текста пароля в представлении регистрации.

18 голосов
/ 01 мая 2017

Если вы используете Swift 3 , попробуйте этот подкласс.

class PasswordTextField: UITextField {

    override var isSecureTextEntry: Bool {
        didSet {
            if isFirstResponder {
                _ = becomeFirstResponder()
            }
        }
    }

    override func becomeFirstResponder() -> Bool {

        let success = super.becomeFirstResponder()
        if isSecureTextEntry, let text = self.text {
            self.text?.removeAll()
            insertText(text)
        }
        return success
    }

}

Почему это работает?

TL; DR: если вы редактируете поле при переключении isSecureTextEntry, убедитесь, что вы вызываете becomeFirstResponder.


Переключение значения isSecureTextEntry работает нормально, пока пользователь не отредактирует текстовое поле -Текстовое поле очищается перед размещением новых символов.Эта предварительная очистка, кажется, происходит во время becomeFirstResponder вызова UITextField.Если этот вызов сочетается с уловкой deleteBackward / insertText (как показано в ответах @ Алексей и @ dwsolberg ), входной текст сохраняется, что, по-видимому, отменяет предварительнуюочистка.

Однако, когда значение isSecureTextEntry изменяется, когда текстовое поле является первым респондентом (например, пользователь вводит свой пароль, переключает кнопку «показать пароль» вперед и назад, а затем продолжает вводить),текстовое поле будет сброшено как обычно.

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

Спасибо @Patrick Ridd за исправление!

15 голосов
/ 22 марта 2015

@ Ответ Эрика работает, но у меня были две проблемы с ним.

  1. Как указывал @malex, любое изменение текста в середине помещает каретку в конце текста.
  2. Я использую rac_textSignal из ReactiveCocoa, и прямое изменение текста не вызовет сигнал.

Мой окончательный код

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    //Setting the new text.
    NSString *updatedString = [textField.text stringByReplacingCharactersInRange:range withString:string];
    textField.text = updatedString;

    //Setting the cursor at the right place
    NSRange selectedRange = NSMakeRange(range.location + string.length, 0);
    UITextPosition* from = [textField positionFromPosition:textField.beginningOfDocument offset:selectedRange.location];
    UITextPosition* to = [textField positionFromPosition:from offset:selectedRange.length];
    textField.selectedTextRange = [textField textRangeFromPosition:from toPosition:to];

    //Sending an action
    [textField sendActionsForControlEvents:UIControlEventEditingChanged];

    return NO;
}

Добавление Swift3 от @Mars:

  func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    let nsString:NSString? = textField.text as NSString?
    let updatedString = nsString?.replacingCharacters(in:range, with:string);

    textField.text = updatedString;


    //Setting the cursor at the right place
    let selectedRange = NSMakeRange(range.location + string.length, 0)
    let from = textField.position(from: textField.beginningOfDocument, offset:selectedRange.location)
    let to = textField.position(from: from!, offset:selectedRange.length)
    textField.selectedTextRange = textField.textRange(from: from!, to: to!)

    //Sending an action
    textField.sendActions(for: UIControlEvents.editingChanged)

    return false;
}
5 голосов
/ 25 мая 2017

@ Ответ Томаса Вербека мне очень помог:

class PasswordTextField: UITextField {

    override var isSecureTextEntry: Bool {
        didSet {
            if isFirstResponder {
                _ = becomeFirstResponder()
            }
        }
    }

    override func becomeFirstResponder() -> Bool {

        let success = super.becomeFirstResponder()
        if isSecureTextEntry, let text = self.text {
            deleteBackward()
            insertText(text)
        }
        return success
    }

}

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

Чтобы исправить это, я заменил deleteBackward() на self.text?.removeAll(), и это сработало как заклинание.

Я бы не добился этого без оригинального решения Томаса, так что спасибо Томасу!

5 голосов
/ 23 января 2013

У меня была похожая проблема.У меня есть текстовые поля логина (secureEntry = НЕТ) и пароля (secureEntry = ДА), встроенные в табличное представление.Я попытался установить

textField.clearsOnBeginEditing = NO;

внутри обоих соответствующих методов делегата (textFieldDidBeginEditing и textFieldShouldBeginEditing), которые не работали.После перехода от поля пароля к полю входа в систему все поле входа в систему будет очищено, если я попытаюсь удалить один символ.Я использовал textFieldShouldChangeCharactersInRange для решения моей проблемы следующим образом:

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (range.length == 1 && textField.text.length > 0) 
    {
        //reset text manually
        NSString *firstPart = [textField.text substringToIndex:range.location]; //current text minus one character
        NSString *secondPart = [textField.text substringFromIndex:range.location + 1]; //everything after cursor
        textField.text = [NSString stringWithFormat:@"%@%@", firstPart, secondPart];

        //reset cursor position, in case character was not deleted from end of 
        UITextRange *endRange = [textField selectedTextRange];
        UITextPosition *correctPosition = [textField positionFromPosition:endRange.start offset:range.location - textField.text.length];
        textField.selectedTextRange = [textField textRangeFromPosition:correctPosition toPosition:correctPosition];

        return NO;
    }
    else
    {
        return YES;
    }
}

range.length == 1 возвращает true, когда пользователь входит в забой, что (как ни странно) единственный раз, когда я вижуполе очищено.

5 голосов
/ 11 апреля 2018

Swift 3 / Swift 4

yourtextfield.clearsOnInsertion = false
yourtextfield.clearsOnBeginEditing = false

Примечание. Это не будет работать, если secureTextEntry = YES.Похоже, по умолчанию iOS очищает текст в текстовых полях защищенной записи перед редактированием, независимо от того, имеет ли значение clearsOnBeginEditing значение ДА или НЕТ.

Простой способ использования класса и его работа 100%

class PasswordTextField: UITextField {

    override var isSecureTextEntry: Bool {
        didSet {
            if isFirstResponder {
                _ = becomeFirstResponder()
            }
        }
    }

    override func becomeFirstResponder() -> Bool {

        let success = super.becomeFirstResponder()
        if isSecureTextEntry, let text = self.text {
            self.text?.removeAll()
            insertText(text)
        }
         return success
    }

}
5 голосов
/ 06 мая 2016

Я перепробовал все решения тут и там и, наконец, пришел с этим переопределением:

- (BOOL)becomeFirstResponder
{
    BOOL became = [super becomeFirstResponder];
    if (became) {
        NSString *originalText = [self text];
        //Triggers UITextField to clear text as first input
        [self deleteBackward];

        //Requires setting text via 'insertText' to fire all associated events
        [self setText:@""];
        [self insertText:originalText];
    }
    return became;
}

Запускает очистку UITextField, а затем восстанавливает исходный текст.

2 голосов
/ 31 августа 2016

Основываясь на решении Алексея, я использую этот подкласс.

class SecureNonDeleteTextField: UITextField {

    override func becomeFirstResponder() -> Bool {
        guard super.becomeFirstResponder() else { return false }
        guard self.secureTextEntry == true else { return true }
        guard let existingText = self.text else { return true }
        self.deleteBackward() // triggers a delete of all text, does NOT call delegates
        self.insertText(existingText) // does NOT call delegates
        return true
    }
}

Изменение заменяющих символов в диапазоне не работает для меня, потому что я время от времени занимаюсь другими вещами, и добавление большего повышает вероятность появления ошибок.

Это хорошо, потому что в значительной степени работает идеально.Единственная странность в том, что последний символ снова отображается, когда вы возвращаетесь в поле.Мне это действительно нравится, потому что оно действует как своего рода заполнитель.

1 голос
/ 24 марта 2014

Если вы хотите использовать secureTextEntry = YES и правильное визуальное поведение для перевозки, вам нужно это:

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

    if (!string.length) {
        UITextPosition *start = [self positionFromPosition:self.beginningOfDocument offset:range.location];
        UITextPosition *end = [self positionFromPosition:start offset:range.length];
        UITextRange *textRange = [self textRangeFromPosition:start toPosition:end];
        [self replaceRange:textRange withText:string];
    }
    else {
       [self replaceRange:self.selectedTextRange withText:string];
    }

    return NO;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...