it-swarm.com.ru

Обнаружить возврат в пустом UITextField

Есть ли способ обнаружить, когда Backspace/Delete нажата клавиша на клавиатуре iPhone на UITextField, которая пуста? Я хочу знать когда Backspace нажимается, только если UITextField пусто.


Основываясь на предложении @Alex Reynolds в комментарии, я добавил следующий код при создании моего текстового поля:

[[NSNotificationCenter defaultCenter] addObserver:self
          selector:@selector(handleTextFieldChanged:)
              name:UITextFieldTextDidChangeNotification
            object:searchTextField];

Это уведомление получено (вызывается функция handleTextFieldChanged), но все равно не при нажатии кнопки Backspace введите пустое поле. Есть идеи?


Кажется, есть некоторая путаница вокруг этого вопроса. Я хочу получить уведомление, когда Backspace клавиша нажата. Вот и все. Но решение также должно работать, когда UITextField уже пусто.

115
marcc

Это может быть длинный выстрел, но это может сработать. Попробуйте установить для текста текстового поля символ пробела нулевой ширины \u200B. Когда клавиша Backspace нажата в текстовом поле, которое кажется пустым, оно фактически удалит ваше пространство. Тогда вы можете просто вставить пространство.

Может не работать, если пользователю удается переместить каретку влево от места.

34
Andrew

Свифт 4:


Подкласс UITextField:

// MyTextField.Swift
import UIKit

protocol MyTextFieldDelegate {
    func textFieldDidDelete()
}

class MyTextField: UITextField {

    var myDelegate: MyTextFieldDelegate?

    override func deleteBackward() {
        super.deleteBackward()
        myDelegate?.textFieldDidDelete()
    }

}

Реализация:

// ViewController.Swift

import UIKit

class ViewController: UIViewController, MyTextFieldDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        // initialize textField
        let input = MyTextField(frame: CGRect(x: 50, y: 50, width: 150, height: 40))

        // set viewController as "myDelegate"
        input.myDelegate = self

        // add textField to view
        view.addSubview(input)

        // focus the text field
        input.becomeFirstResponder()
    }

    func textFieldDidDelete() {
        print("delete")
    }

}

Objective-C:


Подкласс UITextField:

//Header
//MyTextField.h

//create delegate protocol
@protocol MyTextFieldDelegate <NSObject>
@optional
- (void)textFieldDidDelete;
@end

@interface MyTextField : UITextField<UIKeyInput>

//create "myDelegate"
@property (nonatomic, assign) id<MyTextFieldDelegate> myDelegate;
@end

//Implementation
#import "MyTextField.h"

@implementation MyTextField

- (void)deleteBackward {
    [super deleteBackward];

    if ([_myDelegate respondsToSelector:@selector(textFieldDidDelete)]){
        [_myDelegate textFieldDidDelete];
    }
}

@end

Теперь просто добавьте MyTextFieldDelegate к своему UIViewController и установите для UITextFieldsmyDelegate значение self:

//View Controller Header
#import "MyTextField.h"

//add "MyTextFieldDelegate" to you view controller
@interface ViewController : UIViewController <MyTextFieldDelegate>
@end

//View Controller Implementation
- (void)viewDidLoad {
    //initialize your text field
    MyTextField *input = 
     [[MyTextField alloc] initWithFrame:CGRectMake(0, 0, 70, 30)];

    //set your view controller as "myDelegate"
    input.myDelegate = self;

    //add your text field to the view
    [self.view addSubview:input];
}

//MyTextField Delegate
- (void)textFieldDidDelete {
    NSLog(@"delete");
}
132
Jacob Caraballo

Обновление: см. ответ JacobCaraballo пример, который переопределяет -[UITextField deleteBackward].

Проверьте UITextInput , в частности UIKeyInput имеет deleteBackward метод делегата что всегда вызывается при нажатии клавиши удаления. Если вы делаете что-то простое, то вы можете рассмотреть вопрос о создании подкласса UILabel и приведении его в соответствие с протоколом UIKeyInput, как это делается с помощью SimpleTextInput и this Пример iPhone UIKeyInputПримечание: UITextInput и его родственники (включая UIKeyInput) доступны только в iOS 3.2 и более поздних версиях.

40
ma11hew28

Код вроде следующего:

@interface MyTextField : UITextField
@end

@implementation MyTextField

- (void)deleteBackward
{
    [super deleteBackward];

    //At here, you can handle backspace key pressed event even the text field is empty
}

@end

Наконец, не забудьте изменить свойство пользовательского класса текстового поля на "MyTextField"

31
Jeffrey Loo

Быстрая реализация:

import UIKit

protocol PinTexFieldDelegate : UITextFieldDelegate {
    func didPressBackspace(textField : PinTextField)
}

class PinTextField: UITextField {

    override func deleteBackward() {
        super.deleteBackward()

        // If conforming to our extension protocol
        if let pinDelegate = self.delegate as? PinTexFieldDelegate {
            pinDelegate.didPressBackspace(self)
        }
    }
}
17
Ruud Visser

Я нашел другой способ проще, чем subclass решение. Даже немного странно, но работает нормально.

- (BOOL)textView:(UITextView *)textView 
        shouldChangeTextInRange:(NSRange)range 
        replacementText:(NSString *)text
{
    const char * _char = [text cStringUsingEncoding:NSUTF8StringEncoding];
    int isBackSpace = strcmp(_char, "\b");

    if (isBackSpace == -8) {
       // is backspace
    }

    return YES;
}

Немного странно, что результат сравнения равен -8. Может быть, я ошибаюсь в какой-то момент C Programming. Но это правильная работа;)

17
Jerapong Nampetch

Попробуйте delegate

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

Затем проверьте, если range.length == 1, который, кажется, имеет место, когда backspace ударил.

10
Niklas Alvaeus

пожалуйста, используйте приведенный ниже код, он поможет вам обнаружить клавишу удаления клавиатуры, даже если ваше текстовое поле пусто.

Цель C:

- (BOOL)keyboardInputShouldDelete:(UITextField *)textField { return YES; }

Swift:

func keyboardInputShouldDelete(_ textField: UITextField) -> Bool { return true }
10
Pritesh

Ответ Никласа Алвеуса помог мне с подобной проблемой

Я ограничивал вход определенным набором символов, но он игнорировал символы возврата. Поэтому мне пришлось проверить range.length == 1 перед обрезкой NSString. Если это правда, я просто возвращаю строку и не обрезаю ее. Увидеть ниже

 - (BOOL) textField:(UITextField *)textField 
          shouldChangeCharactersInRange:(NSRange)range 
          replacementString:(NSString *)string
 {
     NSCharacterSet *nonNumberSet = 
      [[NSCharacterSet characterSetWithCharactersInString:@"0123456789."] 
         invertedSet];

    if (range.length == 1) {
       return string;
    }
    else {
       return ([string stringByTrimmingCharactersInSet:nonNumberSet].length > 0);
    }   
 }
8
Ben Call

Да, используйте метод ниже, чтобы обнаружить возврат, когда textField пуст.

Нужно добавить ITextFieldDelegate

yourTextField.delegate = self (ОБЯЗАТЕЛЬНО ТРЕБУЕТСЯ)

Swift:

func keyboardInputShouldDelete(_ textField: UITextField) -> Bool { 
    return true
}

Цель C:

- (BOOL)keyboardInputShouldDelete:(UITextField *)textField { 
    return YES; 
}
5
Himanshu padia

Для тех, у кого проблемы с ответ Джейкоба Я реализовал свой подкласс текстового поля следующим образом, и он прекрасно работает!

#import <UIKit/UIKit.h>

@class HTTextField;

@protocol HTBackspaceDelegate <NSObject>

@optional
- (void)textFieldDidBackspace:(HTTextField*)textField;
@end

@interface HTTextField : UITextField<UIKeyInput>

@property (nonatomic, assign) id<HTBackspaceDelegate> backspaceDelegate;

@end


#import "HTTextField.h"

@implementation HTTextField

- (void)deleteBackward {
    [super deleteBackward];
    if ([self.backspaceDelegate respondsToSelector:@selector(textFieldDidBackspace:)]){
        [self.backspaceDelegate textFieldDidBackspace:self];
    }
}

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

    if (![textField.text length] && [[[UIDevice currentDevice] systemVersion] intValue] >= 8) {
        [self deleteBackward];
    }

    return shouldDelete;
}

@end
4
furkan3ayraktar

Лучшее использование, которое я нашел для обнаружения возврата, это обнаружение, когда пользователь нажал клавишу возврата в пустом UITextField. Например, если у вас есть "всплывающие" получатели в почтовом приложении, когда вы нажимаете клавишу Backspace в UITextField, он выбирает последнего "всплывающего" получателя.

Это можно сделать аналогично ответу Джейкоба Карабальо. Но в ответе Джейкоба, если у UITextField остается один символ, когда вы нажимаете клавишу Backspace, к моменту получения сообщения делегата UITextField уже будет пустым, поэтому вы эффективно обнаруживаете backspace в текстовом поле, содержащем не более одного символа.

На самом деле, если вы хотите обнаружить backspace в UITextField с ровно нулем символов (пусто), то вам следует отправить сообщение delegate до вызова super deleteBackward. Например:

#import "MyTextField.h"

//Text field that detects when backspace is hit with empty text
@implementation MyTextField

#pragma mark - UIKeyInput protocol
-(void)deleteBackward
{
  BOOL isTextFieldEmpty = (self.text.length == 0);
  if (isTextFieldEmpty) {
    if ([self.delegate 
         respondsToSelector:@selector(textFieldDidHitBackspaceWithEmptyText:)]) {

        [self.delegate textFieldDidHitBackspaceWithEmptyText:self];
        }
    }
    [super deleteBackward];
}
@end

Интерфейс для такого текстового поля будет выглядеть примерно так:

@protocol MyTextFieldDelegate;

@interface MyTextField : UITextField
@property(nonatomic, weak) id<MyTextFieldDelegate> delegate;
@end

@protocol MyTextFieldDelegate <UITextFieldDelegate>
@optional
-(void)textFieldDidHitBackspaceWithEmptyText:(MyTextField *)textField;
@end
3
Sam

В iOS 6 метод deleteBackward вызывается в UITextField при нажатии клавиши Backspace, в том числе при пустом поле. Таким образом, вы можете создать подкласс UITextField и предоставить собственную реализацию deleteBackward (также вызывая super).

Я все еще поддерживаю iOS 5, хотя мне нужно сочетание ответа Эндрю и этого.

2
tracy

:) только для заголовка "Определить возврат", где я использую UIKeyboardTypeNumberPad.

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

- (BOOL)textField:(UITextField *)textField 
        shouldChangeCharactersInRange:(NSRange)range 
        replacementString:(NSString *)string
{
    NSLog([NSString stringWithFormat:@"%d", [string length]]);
}

Поскольку с UIKeyboardTypeNumberPad пользователь может вводить только Number или backspace, поэтому, когда длина строки равна 0, это должен быть ключ backspace.

Надеюсь, что вышесказанное поможет.

1
Jason Lee

Вместо того, чтобы пытаться заранее составить, что будет в текстовом поле или выяснить, какой специальный символ был введен в методе shouldChangeCharactersInRange, я бы предложил сделать следующее:

[self performSelector:@selector(manageSearchResultsDisplay) 
           withObject:nil 
           afterDelay:0];

Это позволяет вам вызывать метод непосредственно после завершения текущей операции. Что здорово в этом, так это то, что к моменту завершения измененное значение уже будет в UITextField. В этот момент вы можете просто проверить его длину и/или проверить на основе того, что там.

1
Aaron

В .h файл добавить делегата UIKeyInput

- (BOOL)keyboardInputShouldDelete:(UITextField *)textField {

if ([textField isEqual:_txtFirstDigit]) {

}else if([textField isEqual:_txtSecondDigit]) {
    [_txtFirstDigit becomeFirstResponder];

}else if([textField isEqual:_txtThirdDigit]) {
    [_txtSecondDigit becomeFirstResponder];

}else if([textField isEqual:_txtFourthDigit]) {
    [_txtThirdDigit becomeFirstResponder];
}
return YES;
}   

улучшено форматирование

1
Anjali Prasad

Самый популярный ответ отсутствует одна вещь - возможность определить, было ли текстовое поле пустым или нет.

То есть, когда вы переопределяете метод deleteBackwards () подкласса TextField, вы все равно не знаете, было ли текстовое поле уже пустым. (Как до, так и после deleteBackwards (), textField.text! является пустой строкой: "")

Вот мое улучшение с проверкой на пустоту перед удалением.

1. Создайте протокол делегата, который расширяет UITextFieldDelegate

protocol MyTextFieldDelegate: UITextFieldDelegate {
    func textField(_ textField: UITextField, didDeleteBackwardAnd wasEmpty: Bool)
}

2. Подкласс UITextField

class MyTextField: UITextField {
    override func deleteBackward() {
        // see if text was empty
        let wasEmpty = text == nil || text! == ""

        // then perform normal behavior
        super.deleteBackward()

        // now, notify delegate (if existent)
        (delegate as? MyTextFieldDelegate)?.textField(self, didDeleteBackwardAnd: wasEmpty)
    }
}

3. Внедрите свой новый протокол делегата

extension MyViewController: MyTextFieldDelegate {
    func textField(_ textField: UITextField, didDeleteBackwardAnd wasEmpty: Bool) {
        if wasEmpty {
            // do what you want here...
        }
    }
}
1
Tim

Подкласс UITextField не работал для меня на iOS 8.3, deleteBackward никогда не вызывался.

Вот решение, которое я использовал, работает на всех версиях iOS 8 и должно работать на других версиях iOS

for textField in textFields {
            textField.text = " "
}

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
        if string == "" && textField.text == " "   {
            // Do stuff here
            return false
        }
        return true
}
1
joel.d

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

protocol MyTextFieldDelegate : UITextFieldDelegate {
    func textFieldDidDelete(textField: MyTextField, hasValue: Bool)
}

override func deleteBackward() {
    let currentText = self.text ?? ""
    super.deleteBackward()
    let hasValue = currentText.isEmpty ? false : true
    if let delegate = self.delegate as? MyTextFieldDelegate {
        delegate.textFieldDidDelete(textField: self, hasValue: hasValue)
    }
}
1
Hemang