140

有什么方法可以检测何时在空的 iPhone 键盘上按下Backspace/键?我想知道只有在为空时才按下。DeleteUITextFieldBackspaceUITextField


根据@Alex Reynolds 在评论中的建议,我在创建文本字段时添加了以下代码:

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

收到此通知(handleTextFieldChanged调用函数),但当我Backspace在空白字段中按下键时仍然没有。有任何想法吗?


这个问题似乎有些混乱。我想在Backspace按下键时收到通知。而已。UITextField但是当已经为空时,该解决方案也必须有效。

4

28 回答 28

174

斯威夫特 4:


子类UITextField

// MyTextField.swift
import UIKit

protocol MyTextFieldDelegate: AnyObject {
    func textFieldDidDelete()
}

class MyTextField: UITextField {

    weak 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")
    }

}

目标-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并将您的UITextFields myDelegate设置为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");
}
于 2013-04-04T01:52:25.497 回答
41

更新:有关覆盖的示例,请参阅JacobCaraballo 的答案-[UITextField deleteBackward]

签出UITextInput,特别是UIKeyInput有一个deleteBackward委托方法,当删除键被按下时总是被调用。如果您正在做一些简单的事情,那么您可能会考虑只是子类UILabel化并使其符合UIKeyInput协议,就像SimpleTextInput和这个iPhone UIKeyInput Example所做的那样。注意:UITextInput及其亲属(包括UIKeyInput)仅适用于 iOS 3.2 及更高版本。

于 2011-07-09T22:14:16.327 回答
39

这可能是一个长镜头,但它可以工作。尝试将文本字段的文本设置为零宽度空格字符\u200B。当在显示为空的文本字段上按下退格键时,它实际上会删除您的空间。然后你可以重新插入空间。

如果用户设法将插入符号移动到空间的左侧,则可能无法正常工作。

于 2009-12-30T23:10:04.397 回答
31

代码如下:

@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”

于 2013-04-24T02:41:03.413 回答
22

快速实现:

import UIKit

// Extend from PinTextFieldDelegate instead of UITextFieldDelegate in your class
protocol PinTextFieldDelegate : 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? PinTextFieldDelegate {
            pinDelegate.didPressBackspace(self)
        }
    }
}
于 2017-01-06T02:46:28.067 回答
18

我建立了比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。但它的正确工作;)

于 2012-02-20T03:33:26.917 回答
12

请使用下面的代码,即使您的文本字段为空,它也会帮助您检测键盘删除键。

目标 C:

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

斯威夫特:

func keyboardInputShouldDelete(_ textField: UITextField) -> Bool { return true }
于 2017-06-05T11:36:51.537 回答
11

试试delegate

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

然后检查是否在被击中range.length == 1时似乎是这种情况。backspace

于 2010-04-16T16:01:07.677 回答
9

Niklas Alvaeus 的回答帮助我解决了类似的问题

我限制了对特定字符集的输入,但它忽略了退格。所以我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);
    }   
 }
于 2010-04-30T13:08:43.577 回答
5

是的,当 textField 为空时,使用以下方法检测退格。

需要添加UITextFieldDelegate

yourTextField.delegate = self (必须)

迅速:

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

目标 C:

- (BOOL)keyboardInputShouldDelete:(UITextField *)textField { 
    return YES; 
}
于 2017-07-26T12:54:58.450 回答
4

对于那些对雅各布的回答有疑问的人,我实现了我的文本字段子类,如下所示,效果很好!

#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
于 2014-10-20T20:46:19.967 回答
3

我发现检测退格的最佳用途是检测用户何时在空白中按下退格UITextField。例如,如果您在邮件应用程序中有“冒泡”收件人,当您在 中按退格键时UITextField,它会选择最后一个“冒泡”收件人。

这可以通过与 Jacob Caraballo 的回答类似的方式完成。但是在 Jacob 的回答中,如果UITextField当您按下退格键时 还剩一个字符,则在收到委托消息时,UITextField将已经为空,因此您有效地检测backspace到最多包含一个字符的文本字段。

实际上,如果您想backspace在 aUITextField上检测到恰好零个字符(空),那么您应该delegate在调用 to 之前将消息发送到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
于 2013-07-11T17:39:32.897 回答
2

在 iOS 6 中,当按下退格键时,会在 UITextField 上调用 deleteBackward 方法,包括当字段为空时。因此,您可以继承 UITextField 并提供您自己的 deleteBackward 实现(也可以调用 super。)

我仍然支持 iOS 5,所以我需要 Andrew 的回答和这个的结合。

于 2012-10-22T18:28:35.337 回答
2

在 .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;
}   

改进的格式

于 2018-03-16T07:01:55.310 回答
1

:) 只是为了标题“检测退格”,我使用UIKeyboardTypeNumberPad.

今晚我也遇到了同样的问题,以下是我的代码来找出它:

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

因为使用UIKeyboardTypeNumberPad,用户只能输入数字或退格,所以当字符串长度为 0 时,它必须是退格键。

希望以上内容对您有所帮助。

于 2011-12-26T12:55:28.500 回答
1

我建议不要尝试预先构造文本字段中的内容或弄清楚shouldChangeCharactersInRange方法中输入了哪些特殊字符,而是建议执行以下操作:

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

这允许您在当前操作完成后直接调用方法。这很酷的是,当它完成时,修改后的值已经在UITextField. 那时,您可以检查它的长度和/或根据那里的内容进行验证。

于 2012-12-04T20:19:49.790 回答
1

在 iOS 8.3 上,子类化 UITextField 对我不起作用,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
}
于 2015-05-20T20:26:11.990 回答
1

Swift 5.1的单个数字文本字段的综合处理程序:

  • 假设您有 textFields 的出口集合(也有连接的代表)

1 步

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

final class MyTextField: UITextField {

    weak var myDelegate: MyTextFieldDelegate?

    override func deleteBackward() {
        let wasEmpty = text == nil || text == ""

        // then perform normal behavior
        super.deleteBackward()

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

2 步

final class ViewController: UIViewController {

    @IBOutlet private var textFields: [MyTextField]!

    override func viewDidLoad() {
        super.viewDidLoad()
        textFields.forEach {
            $0.delegate = self
            $0.myDelegate = self
        }
    }
}

3 步

extension ViewController: UITextFieldDelegate, MyTextFieldDelegate {
    func textFieldHasChanged(with text: String, _ tag: Int, for textField: UITextField) {
        textField.text = text

        if let someTextField = (textFields.filter { $0.tag == tag }).first {
            someTextField.becomeFirstResponder()
        } else {
            view.endEditing(true)
        }
    }

    func textField(_ textField: UITextField, didDeleteBackwardAnd wasEmpty: Bool) {
        // If the user was pressing backward and the value was empty, go to previous textField
        textFieldHasChanged(with: "", textField.tag - 1, for: textField)
    }

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        // Restrict to only digits
        let aSet = NSCharacterSet(charactersIn: "0123456789").inverted
        let compSepByCharInSet = string.components(separatedBy: aSet)
        let numberFiltered = compSepByCharInSet.joined(separator: "")

        guard string == numberFiltered, let text = textField.text else { return false }

        if text.count >= 1 && string.isEmpty {
            // If the user is deleting the value
            textFieldHasChanged(with: "", textField.tag - 1, for: textField)
        } else {
            textFieldHasChanged(with: string, textField.tag + 1, for: textField)
        }

        return false
    }
}
于 2019-12-15T00:32:22.717 回答
1

这是我基于@andrew想法的解决方案:

某处,例如在 viewDidLoad

        textField.delegate = self
        textField.addTarget(self, action: #selector(valueChanged(_:)), for: .editingDidBegin)

接着

    @objc func valueChanged(_ textField: UITextField) {
        textField.text = "\u{200B}"
    }

    override func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        textField.text = string
        if string == "" {
            //backpaspace pressed 
        }
于 2019-12-16T09:20:43.377 回答
1

最常见的答案是缺少一件事——检测文本字段是否为空的能力。

也就是说,当您覆盖 TextField 子类的 deleteBackwards() 方法时,您仍然不知道文本字段是否已经为空。(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...
        }
    }
}
于 2019-01-15T21:50:13.137 回答
1

我已经实现了类似的解决方案,并进行了一些小的改进,这将告诉我在用户点击退格时文本字段是否有任何值。如果按下退格键时文本字段为空,我应该只关注另一个文本字段,这对我的情况很有用。

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)
    }
}
于 2018-05-21T08:07:48.360 回答
0

所有的答案都非常有帮助,我不知道为什么每个人都在走协议路线。你可以用更少的代码和回调函数来做到这一点,比如 -

Swift 5.0 或以上

  1. 制作一个扩展 UITextField 的自定义文本字段类并覆盖 deleteBackward 函数-

    类 CustomTextField: UITextField {

     var backButtonPressedInEmptyTextField: (()->())?
    
     override func deleteBackward() {
         super.deleteBackward()
         if let text = self.text, text.count == 0{
             backButtonPressedInEmptyTextField?()
             print("Back space clicked when textfield is empty")
         }
     }
    

    }

  2. 让我们假设你想在你的 ViewController 中做一些基于它的事情,MyViewController. 因此,在 中MyViewController,只需执行以下操作 -

    类 MyViewController: UIViewController{ @IBOutlet 弱 var sampleTextField: CustomTextField!{ didSet{ sampleTextField.backButtonPressedInEmptyTextField = backButtonPressed() } }

     func backButtonPressed(){
         //do whatever you want
     }
    

    }

我觉得用闭包或回调函数,它更干净。

于 2021-02-24T11:49:44.333 回答
-2

像这样的东西:

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

当然,哈希是针对一个字符串的。

于 2012-08-02T03:25:41.430 回答
-2

使用 TextField 委托方法:

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

在上述方法中添加以下代码以检测删除事件

if(textField == YourTextField)
{
    if ([string length] == 0 && range.length > 0)
    {
        // Your Code after deletion of character
    }
}
于 2014-07-02T09:08:31.487 回答
-3
+ (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;
}
于 2014-03-21T10:33:57.333 回答
-3

您可以检查文本视图/字段的文本以查看它是否为空,并确保在 shouldChangeTextIn 委托方法中替换文本也为空。

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    if (textView.text == "" && text == "") {
        print("Backspace on empty text field.")
    }
    return true
}
于 2020-07-25T21:32:58.320 回答
-4

UITextViewDelegate

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

它对我来说没问题。

中文简体拼音和中文手写输入更新:

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

根据文件说:

“如果用户按下deleteKey,则范围的长度为 1 并且一个空字符串对象替换该单个字符。”

于 2013-03-30T06:59:07.990 回答
-4

为了保持简单,这是您需要检查的唯一条件

     if (range.length==1)
于 2013-06-05T05:44:58.427 回答