Как обнаружить ключ удаления на UITextField в iOS 8?

Я подклассифицировал UITextField и реализовал метод deleteBackward для метода UIKeyInput для обнаружения обратного пространства. Это отлично работает на iOS 7, но не на iOS 8.

deleteBackward больше не вызывается на UITextField, когда я нажимаю клавишу backspace.

Я проверил документацию и примечания к выпуску, и ничто не указывает на причину, почему это может произойти. Любые указатели?

Ответ 1

Вы должны посмотреть пример MBContactPicker в github. Удаление контактов в MBContactPicker с помощью кнопки Backspace на iOS8, проверенной мной. И это работает очень! Вы можете использовать его как пример.

Автор MBContactPicker использует следующий метод: когда UITextField должен быть пустым (или до вызова getFirstResponder, когда он пуст), он сохраняет один символ пробела. И затем, когда вы нажимаете кнопку Backspace (когда фокус установлен на конец текста вашего UITextField), метод

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

будет работать. В нем вы должны использовать проверку следующим образом:

NSString *resultString = [textField.text stringByReplacingCharactersInRange:range withString:text];
BOOL isPressedBackspaceAfterSingleSpaceSymbol = [text isEqualToString:@""] && [resultString isEqualToString:@""] && range.location == 0 && range.length == 1;
if (isPressedBackspaceAfterSingleSpaceSymbol) {
    //  your actions for deleteBackward actions
}

Итак, вы всегда должны контролировать, что UITextField содержит одиночные пробелы.

Это не взломать. Таким образом, пользователь не заметил, что какое-то поведение было изменено.

Ответ 2

Многие люди говорили, что это ошибка, но поскольку эта проблема все еще существует в GM, я начинаю думать, что это может быть изменение в логике. С учетом сказанного я написал этот бит кода для своего приложения и протестировал его на iOS 7-8.

Добавьте следующий подкласс к вашему подклассу UITextField.

- (BOOL)keyboardInputShouldDelete:(UITextField *)textField {
    BOOL shouldDelete = YES;

    if ([UITextField instancesRespondToSelector:_cmd]) {
        BOOL (*keyboardInputShouldDelete)(id, SEL, UITextField *) = (BOOL (*)(id, SEL, UITextField *))[UITextField instanceMethodForSelector:_cmd];

        if (keyboardInputShouldDelete) {
            shouldDelete = keyboardInputShouldDelete(self, _cmd, textField);
        }
    }

    BOOL isIos8 = ([[[UIDevice currentDevice] systemVersion] intValue] == 8);
    BOOL isLessThanIos8_3 = ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.3f);

    if (![textField.text length] && isIos8 && isLessThanIos8_3) {
        [self deleteBackward];
    }

    return shouldDelete;
}

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

Чтобы объяснить немного, вызывают супер реализацию этого метода, чтобы избежать потери кода. После вызова -deleteBackward, если текст отсутствует, а версия iOS находится между 8-8.2.

РЕДАКТИРОВАТЬ: 1/22/15

Также может оказаться полезным подкласс метода -deleteBackward вашего подкласса UITextField. Это исправляет несколько условных ошибок. Один из них, если вы используете пользовательскую клавиатуру. Вот пример метода.

- (void)deleteBackward {
    BOOL shouldDismiss = [self.text length] == 0;

    [super deleteBackward];

    if (shouldDismiss) {
        if ([self.delegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)]) {
            [self.delegate textField:self shouldChangeCharactersInRange:NSMakeRange(0, 0) replacementString:@""];
        }
    }
}

РЕДАКТИРОВАТЬ: 4/13/15

Как комментировал @Gee.E, iOS 8.3 исправил эту проблему. Код был обновлен, чтобы отразить изменения.

Ответ 3

Вы можете обнаружить, когда пользователь удаляет текст, используя обратное пространство, реализуя метод делегирования UITextField:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (range.length==1 && string.length==0)
        NSLog(@"backspace tapped");

    return YES;
}

Ответ 4

Swift 2.2:

func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {

    if text == "" {
      print("Backspace has been pressed")
    }

    return true
}

Ответ 5

В iOS8 некоторые пользовательские клавиатуры удаляют целые слова, поэтому проверьте только строку string.length.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (string.length==0) { //Delete any cases
       if(range.length > 1){
          //Delete whole word
       }
       else if(range.length == 1){
          //Delete single letter
       }
       else if(range.length == 0){
          //Tap delete key when textField empty
       }  
    }  
    return YES;
}

Ответ 6

версия Swift 2.0 для обнаружения удаления BackSpace, ссылка на кодовое сообщение от almas

//For Detecting Backspace based Deletion of Entire Word in TextField
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { 
    if (range.length == 1 && string.isEmpty){
        print("Used Backspace")
    }
return true
}

Ответ 7

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
   const char * _char = [string cStringUsingEncoding:NSUTF8StringEncoding];
   int isBackSpace = strcmp(_char, "\b");

   if (isBackSpace == -8) {
     NSLog(@"Backspace was pressed");
   }

return YES;

}

В основном этот метод определяет, какую кнопку вы нажимаете (или только что нажали). Этот ввод вводится как NSString. Мы преобразуем этот NSString в тип C char, а затем сравниваем его с традиционным символом обратного пространства (\ b). Тогда, если этот strcmp равен -8, мы можем обнаружить его как backspace.

Ответ 8

swift 2:

if (string.characters.count == 0 && range.length == 1) {
            return true
}

вы должны использовать это как string.characters.count