Wykryj backspace w pustym UITextField

Czy Jest jakiś sposób na wykrycie kiedy Backspace/klawisz Delete jest wciśnięty w klawiaturze iPhone ' a na UITextField, który jest pusty? Chcę wiedzieć kiedy Backspace jest wciśnięty tylko wtedy, gdy {[1] } jest puste.


Na podstawie sugestii @Alex Reynolds w komentarzu, dodałem następujący kod podczas tworzenia mojego pola tekstowego:

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

To powiadomienie jest odbierane( wywołana jest funkcjahandleTextFieldChanged), ale nadal nie kiedy nacisnę klawisz Backspace w puste pole. Jakieś pomysły?


Wydaje się być pewne zamieszanie wokół tego pytania. Chcę otrzymać powiadomienie po naciśnięciu klawisza Backspace . To wszystko. Ale rozwiązanie musi działać również wtedy, gdy UITextField jest już puste.

Author: AsimRazaKhan, 2009-12-30

23 answers

To może być ryzykowne, ale może się udać. Spróbuj ustawić tekst pola tekstowego na znak spacji o zerowej szerokości \u200B. Gdy backspace zostanie naciśnięty na pole tekstowe, które wydaje się puste, spowoduje to usunięcie spacji. Następnie możesz po prostu ponownie włożyć przestrzeń.

Może nie działać, jeśli użytkownikowi uda się przesunąć karetkę na lewo od miejsca.

 33
Author: Andrew,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-30 23:10:04

Swift 4:


Podklasa UITextField:

// MyTextField.swift
import UIKit

protocol MyTextFieldDelegate {
    func textFieldDidDelete()
}

class MyTextField: UITextField {

    var myDelegate: MyTextFieldDelegate?

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

}

Realizacja:

// 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:


Podklasa 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

Teraz wystarczy dodać MyTextFieldDelegate do swojego UIViewController i ustawić swój UITextFields myDelegate do 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");
}
 109
Author: Jacob Caraballo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-19 18:56:52

W tym przypadku nie jest to możliwe, ponieważ nie jest to możliwe.

Zobacz UITextInput, w szczególności UIKeyInput ma deleteBackward metoda delegate, która zawsze jest wywoływana po naciśnięciu klawisza delete. Jeśli robisz coś prostego, możesz rozważyć tylko podklasowanie UILabel i dostosowanie go do protokołu UIKeyInput, Jak to zostało zrobione przez SimpleTextInput i ten iPhone Uikeyinput przykład. Uwaga: [1]} i jego krewni (w tym UIKeyInput) są dostępne tylko w systemie iOS 3.2 i nowszych.

 36
Author: ma11hew28,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:53

Kod podobny do następującego:

@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

W końcu zapomnij zmienić właściwość niestandardowej klasy pola tekstowego na"MyTextField"

 30
Author: Jeffrey Loo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-24 02:41:03

Założyłem inny sposób łatwiejszy niż subclass rozwiązanie. Nawet trochę dziwne, ale Działa ok.

- (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;
}
To trochę dziwne, bo wynik porównania to -8. Może się mylę w jakimś punkcie C Programming. Ale dobrze działa;)
 17
Author: Jerapong Nampetch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-30 15:03:08

Szybka realizacja:

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
Author: Ruud Visser,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-06 02:46:28

Spróbuj delegate

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

Następnie sprawdź, czy range.length == 1, co wydaje się mieć miejsce, gdy backspace jest trafiony.

 10
Author: Niklas Alvaeus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-30 14:55:11

Użyj poniższego kodu, który pomoże Ci wykryć klawisz usuwania klawisza, nawet jeśli textfield jest pusty.

Cel C:

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

Swift:

func keyboardInputShouldDelete(_ textField: UITextField) -> Bool { return true }
 9
Author: Pritesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-20 10:22:14

Odpowiedź Niklasa Alvaeus pomogła mi w podobnym problemie

Ograniczałem wpis do określonego zestawu znaków, ale ignorowałem spacje. Więc przed przycinaniem NSString kazałem sprawdzić to range.length == 1. Jeśli to prawda, po prostu zwracam ciąg i nie przycinam go. Patrz poniżej

 - (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
Author: Ben Call,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-03 14:16:10

Dla tych, którzy mają problemy z Jacob ' s answer zaimplementowałem podklasę textfield w następujący sposób i działa świetnie!

#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
Author: furkan3ayraktar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:40

Yup, użyj poniższej metody, aby wykryć backspace, gdy pole tekstowe jest puste.

Należy dodać UITextFieldDelegate

YourTextField.delegate = self (must REQUIRED)

Swift:

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

Cel C:

- (BOOL)keyboardInputShouldDelete:(UITextField *)textField { 
    return YES; 
}
 4
Author: Himanshu padia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-26 12:54:58

Najlepszym zastosowaniem, jakie znalazłem do wykrywania backspace, jest wykrywanie, gdy użytkownik nacisnął backspace w pustym UITextField. Na przykład, jeśli masz "bubbled" odbiorców w aplikacji mail, po naciśnięciu backspace w UITextField, wybiera on ostatniego "bubbled" odbiorcy.

Można to zrobić w podobny sposób jak odpowiedź Jacoba Caraballo. Ale w odpowiedzi Jacoba, jeśli UITextField ma jeden znak w lewo po naciśnięciu backspace, do czasu odebrania wiadomości delegata, UITextField będzie jest już pusty, więc skutecznie wykrywasz backspace na polu tekstowym z co najwyżej jednym znakiem.

Właściwie, jeśli chcesz wykryć backspace na UITextField z dokładnie zerowymi znakami (pustymi), powinieneś wysłać wiadomość do delegate przed wywołaniem do super deleteBackward. Na przykład:

#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

Interfejs dla takiego pola tekstowego wyglądałby mniej więcej tak:

@protocol MyTextFieldDelegate;

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

@protocol MyTextFieldDelegate <UITextFieldDelegate>
@optional
-(void)textFieldDidHitBackspaceWithEmptyText:(MyTextField *)textField;
@end
 3
Author: Sam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-30 15:22:09

W systemie iOS 6 metoda deleteBackward jest wywoływana w polu UITextField po naciśnięciu backspace, także wtedy, gdy pole jest puste. Możesz więc podklasować UITextField i zapewnić własną implementację deleteBackward(wywołując również super.)

Nadal wspieram iOS 5, więc potrzebuję kombinacji odpowiedzi Andrew i tego.

 2
Author: tracy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-22 18:28:35

:) tylko dla tytułu "Detect backspace", gdzie używam UIKeyboardTypeNumberPad.

Ja również dziś spotykam się z tym samym pytaniem, a poniżej znajduje się mój kod, aby go dowiedzieć:

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

Ponieważ z UIKeyboardTypeNumberPad, użytkownik może wprowadzić tylko liczbę lub backspace, więc jeśli długość łańcucha wynosi 0, musi to być klucz backspace.

Mam nadzieję, że powyższe pomoże.

 1
Author: Jason Lee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-30 14:59:53

Zamiast próbować prekonstrukcji tego, co będzie w polu tekstowym lub dowiedzieć się, jaki znak specjalny został wprowadzony w metodzie shouldChangeCharactersInRange, sugerowałbym wykonanie następujących czynności:

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

Pozwala to na wywołanie metody bezpośrednio po zakończeniu bieżącej operacji. Najfajniejsze w tym jest to, że do czasu zakończenia, zmodyfikowana wartość będzie już w UITextField. W tym momencie możesz po prostu sprawdzić jego długość i / lub zweryfikować na podstawie tego, co tam jest.

 1
Author: Aaron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-30 14:59:59

Podklasowanie UITextField nie działało dla mnie na iOS 8.3, deleteBackward nigdy nie został wywołany.

Oto rozwiązanie, którego użyłem, działa na wszystkich wersjach iOS 8 i powinno działać również na innych wersjach 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
Author: joel.d,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-20 20:26:11

W .h file add uikeyinput delegate

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

Ulepszone Formatowanie

 1
Author: Anjali Prasad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-16 07:29:32

Zaimplementowałem podobne rozwiązanie z drobnymi ulepszeniami, które powiedzą mi, że jeśli pole tekstowe ma jakąkolwiek wartość, podczas gdy użytkownik dotknął backspace. Jest to przydatne w moim przypadku, gdy powinienem skupić się tylko na innym polu tekstowym, jeśli pole tekstowe jest puste po naciśnięciu 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)
    }
}
 0
Author: Hemang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-21 08:07:48

Użycie metody delegata TextField:

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

Dodaj następujący kod w powyższej metodzie, aby wykryć Zdarzenie delete

if(textField == YourTextField)
{
    if ([string length] == 0 && range.length > 0)
    {
        // Your Code after deletion of character
    }
}
 -1
Author: kalim sayyad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-02 09:29:46

Aby zachować to proste tutaj jest jedynym warunkiem trzeba sprawdzić

     if (range.length==1)
 -2
Author: Bhumit Mehta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-05 07:08:52
+ (BOOL)detectBackspaceOnly:(NSString *)string
{
    for(int i=0 ; i<string.length ; i++){
        unichar caract = [string characterAtIndex:i];
        if(caract != ' ' && caract != '\n')
            return NO;
    }

    return YES;
}
 -2
Author: K-AnGaMa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-21 10:33:57

Coś takiego:

- (BOOL)textField:(UITextField *)textField 
        shouldChangeCharactersInRange:(NSRange)range 
        replacementString:(NSString *)string       
{  
    if (![text hash] && ![textField.text length])  
        [self backspaceInEmptyTextField];  
}

Oczywiście hash jest dla jednego ciągu znaków.

 -2
Author: user1375355,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-30 15:04:13

W UITextViewDelegate:

- (BOOL)               textView:(UITextView *)textView 
        shouldChangeTextInRange:(NSRange)range 
                replacementText:(NSString *)text
{
    if(text isEqualToString:@"");
    {
        NSLog(@"press backspace.");
    }
}
Dla mnie Działa ok.

Aktualizacja dla chińskiego uproszczonego pinyin i chińskiego pisma ręcznego:

- (BOOL)               textView:(UITextView *)textView 
        shouldChangeTextInRange:(NSRange)range 
                replacementText:(NSString *)text
{
    if (range.length > 0 && [text isEqualToString:@""]) {
        NSLog(@"press Backspace.");
    }
    return YES;
}

Na podstawie dokumentu napisano:

"Jeśli użytkownik naciśnie deleteKey, długość zakresu wynosi 1, A pusty obiekt string zastępuje ten pojedynczy znak."

 -4
Author: joker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-15 13:12:37