iOS 6 UITextField Secure — как обнаружить удаление всех символов назад?

В iOS 6, если вы вводите текст в защищенное текстовое поле, переходите в другое текстовое поле, затем возвращаетесь в защищенное текстовое поле и нажимаете клавишу Backspace, все символы удаляются. Меня это устраивает, однако я пытаюсь включить/отключить кнопку в зависимости от того, есть ли в этом защищенном текстовом поле символы или нет. Я знаю, как определить, какие символы находятся в полях, и если нажата клавиша Backspace, но у меня возникают проблемы с определением того, как определить, происходит ли очистка всех символов.

Это метод делегата, который я использую для получения нового текста поля, но я не могу понять, как получить новый текст (при условии, что новый текст будет просто пустой строкой), если забой удар, который очищает все символы.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    //returns the "new text" of the field
    NSString * text = [textField.text stringByReplacingCharactersInRange:range withString:string];
}

Любая помощь горячо приветствуется.

Спасибо!


person crizzwald    schedule 27.05.2013    source источник
comment
если string, переданный через параметр replacementString:, представляет собой пустую строку нулевой длины, а range.length больше нуля, я бы сказал, что у вас все очищается.   -  person Michael Dautermann    schedule 27.05.2013
comment
просто нажав клавишу Backspace и удалив один символ, строковый параметр станет пустым и будет иметь нулевую длину, так что это не сработает.   -  person crizzwald    schedule 27.05.2013
comment
range возвращается, как если бы это был один пробел, так что это тоже не работает. и я не уверен, что вы имеете в виду под [собственной длиной]   -  person crizzwald    schedule 27.05.2013


Ответы (7)


Я использую это решение. Он не нуждается в локальных переменных и правильно устанавливает позицию курсора после удаления символа.

Это гибрид этих решений:


 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
    {
        if (range.location > 0 && range.length == 1 && string.length == 0)
        {
            // Stores cursor position
            UITextPosition *beginning = textField.beginningOfDocument;
            UITextPosition *start = [textField positionFromPosition:beginning offset:range.location];
            NSInteger cursorOffset = [textField offsetFromPosition:beginning toPosition:start] + string.length;

            // Save the current text, in case iOS deletes the whole text
            NSString *text = textField.text;


            // Trigger deletion
            [textField deleteBackward];


            // iOS deleted the entire string
            if (textField.text.length != text.length - 1)
            {
                textField.text = [text stringByReplacingCharactersInRange:range withString:string];

                // Update cursor position
                UITextPosition *newCursorPosition = [textField positionFromPosition:textField.beginningOfDocument offset:cursorOffset];
                UITextRange *newSelectedRange = [textField textRangeFromPosition:newCursorPosition toPosition:newCursorPosition];
                [textField setSelectedTextRange:newSelectedRange];
            }

            return NO;
        }

        return YES;
    }
person Sascha Manuel Hameister    schedule 19.06.2013

Наконец-то понял это для тех, кто хочет узнать, как определить, когда backspace очистит все символы безопасного UITextField:

UITextField:

self.passwordTextField

Частная собственность (инициализирована NO в инициализации - вероятно, не нужна):

self.passwordFirstCharacterAfterDidBeginEditing

Методы UITextFieldDelegate:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    //if text is blank when first editing, then first delete is just a single space delete
    if([textField.text length] == 0 && self.passwordFirstCharacterAfterDidBeginEditing)
        self.passwordFirstCharacterAfterDidBeginEditing = NO;

    //if text is present when first editing, the first delete will result in clearing the entire password, even after typing text
    if([textField.text length] > 0 && self.passwordFirstCharacterAfterDidBeginEditing && [string length] == 0 && textField == self.passwordTextField)
    {
        NSLog(@"Deleting all characters");
        self.passwordFirstCharacterAfterDidBeginEditing = NO;
    }
    return YES;
}

-(void)textFieldDidBeginEditing:(UITextField *)textField
{
    if(textField == self.passwordTextField)
    {
        self.passwordFirstCharacterAfterDidBeginEditing = YES;
    }
}

Я надеюсь, что это кому-то поможет, и я также надеюсь, что Apple просто создаст метод делегата, который вызывается, когда безопасное текстовое поле очищается удалением — это кажется очень громоздким, но это работает.

person crizzwald    schedule 28.05.2013
comment
Это было единственное решение, которое сработало для меня с UITextFields, встроенным в UITableViewCells. - person Keller; 19.06.2015

Защищенные текстовые поля очищаются при начале редактирования на iOS6+, независимо от того, удаляете вы текст или вводите его. Проверка того, равна ли длина строки замены 0, работает, если текстовое поле очищено от возврата, но раздражает то, что параметры диапазона и строки замены на textField:shouldChangeCharactersInRange:replacementString: неверны, если текст очищается при вводе текста. Это было мое решение:

1) Зарегистрируйтесь для получения textFieldTextDidChange уведомлений.

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(textFieldTextDidChange:)
                                             name:UITextFieldTextDidChangeNotification
                                           object:nil];

2) Повторно вызвать метод делегата textField:shouldChangeCharactersInRange:replacementString:, если текстовое поле защищено и могло быть очищено.

- (void)textFieldTextDidChange:(NSNotification *)notification
{
    if (textField.secureTextEntry && textField.text.length <= 1) {
        [self.textField.delegate textField:self.textField
             shouldChangeCharactersInRange:NSMakeRange(0, textField.text.length)
                         replacementString:textField.text];
    }
}
person benzguo    schedule 20.10.2013

Принятое решение не включает кнопку. Это фактически изменяет поведение возврата на безопасное текстовое поле.

Это решение Swift действительно решает вопрос, правильно информируя делегата о фактической строке, которая будет установлена ​​в текстовом поле, в том числе при нажатии клавиши Backspace. Затем этот делегат может принять решение.

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

    if let text = textField.text {
        let oldText = text.copy()
        var resultString = (text as NSString).stringByReplacingCharactersInRange(range, withString: string) as NSString
        let inputString = string as NSString
        if range.location > 0 && range.length == 1 && inputString.length == 0 {//Backspace pressed
                textField.deleteBackward()
                shouldChange = false

                if let updatedText = textField.text as NSString? {
                    if updatedText.length != oldText.length - 1 {
                        resultString = ""
                    }
                }
        }
        self.delegate?.willChangeTextForCell(self, string: resultString as String)
    }

    return shouldChange
}
person Wouter Scholtens    schedule 21.10.2016

Я столкнулся с той же проблемой, я хотел определить, когда backspace очистит все символы, чтобы я мог отключить некоторые другие кнопки на экране. Так вот как я этого добился.

-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
    _checkForDelete = NO;
    if (textField.isSecureTextEntry && textField.text.length > 0) {
        _checkForDelete = YES;
    }
    return YES;
}

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (_checkForDelete && string.length == 0) {
        _checkForDelete = NO;
        //Do whatever you want to do in this case, 
        //because all the text is going to be cleared.
    }
    return YES
}

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

person Junaid Rehmat    schedule 10.08.2017

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

Ниже приведен метод UITextFieldDelegate, я вызываю пользовательский метод делегата didChangeValueForTextField, поскольку моя кнопка, которую я хочу включить, находится за пределами этого класса.

Класс, реализующий UITextFieldDelegate

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString *newValue = [textField.text stringByReplacingCharactersInRange:range withString:string];
BOOL shouldReturn = YES;

if (range.location > 0 && range.length == 1 && string.length == 0){
    [textField deleteBackward];

    if ([textField.text isEmptyCheck]) {  // Check if textField is empty
        newValue = @"";
    }

    shouldReturn = NO;
}

if(self.delegate && [self.delegate respondsToSelector:@selector(didChangeValueForField:withNewValue:)]) {
    [self.delegate didChangeValueForField:textField withNewValue:newValue];
}

return shouldReturn;

}

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

Класс, содержащий кнопку для включения

 - (void)didChangeValueForField:(UITextField *)textField withNewValue:(NSString *)value {
  // Update values used to validate/invalidate the button.
  // I updated a separate model here.

  // Enable button based on validity
  BOOL isEnabled = [self allFieldsValid];  //  Check all field values that contribute to the button being enabled.

  self.myButton.enabled = isEnabled;

}
person Zaff    schedule 21.02.2016

свифт3.0 - работает.

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replaceString string: String) -> Bool {

    if textField == passwordTextfield {

        if range.location > 0 && range.length == 1 && string.characters.count == 0 {

            if let textString = textField.text {
                // iOS is trying to delete the entire string
                let index = textString.index(textString.endIndex, offsetBy: -1)
                textField.text = textString.substring(to: index)
                return false
            }

        }else if range.location == 0 {
            return true
        }else {
            if let textString = textField.text {
                textField.text = textString + string
                return false
            }
        }


    }
    return true
}
person xidaMM    schedule 09.05.2017