【问题标题】:Can I detect the delete key even if the UITextField is empty?即使 UITextField 为空,我也可以检测到删除键吗?
【发布时间】:2011-08-22 22:45:35
【问题描述】:

当 UITextField 不包含任何内容时,按下键盘的删除键不会调用任何 UITextFieldDelegate 的方法。

我怎样才能检测到它?

编辑: 似乎没有简单的方法可以做到这一点。我能找到的最有用的链接是:

  1. UITextField : Any way to detect the Delete key event when the field is empty ?

  2. How to get the actual key pressed in a UITextField

简而言之,我的解决方案是在文本字段的开头放置一个永久空格。并进行其他必要的更改(textFieldShouldReturn:、textField:shouldChangeCharactersInRange:replacementString: 等)。

【问题讨论】:

标签: iphone ios uitextfield


【解决方案1】:

在上面放一个不可见的按钮。

【讨论】:

    【解决方案2】:

    可以在上面放一个按钮,但这有点脆弱,因为键盘布局可能会随着不同的 iOS 版本而改变,而且对于不同的语言肯定会有不同的键盘布局。

    查看“管理文本字段和文本视图”Apple 文档。我确定有办法做到这一点。它类似于 UITextField 实现了一个协议来获取键事件。其中一个关键事件可能是删除键,因此您可以覆盖任何接收这些事件的方法并以这种方式获取它。

    【讨论】:

    • 我阅读了文档。找不到您提到的“关键事件”。请您提供更明确的信息吗?
    • 对不起,我试过了,但它看起来不像我想的那样工作: UITextField *tf = [UITextField new]; BOOL r = [tf respondsToSelector:@selector(deleteBackward:)];我希望上面的'r'返回true。所以也许 UITextField 在内部实现了这些方法,在一个私有子类中,所以你不能重写这个方法来做你说的。不知道。对不起。
    • 没关系。不需要道歉。愿意尝试所有的可能性。谢谢。
    • 好的,我有一个想法,听听所有通知,看看是否有删除键生成的通知。当我按下删除时,它看起来像是生成了 UIKeyboardCandidateCorrectionDidChangeNotification 事件。您也许可以使用它来感知删除键。嗯,可以试试。
    • @"UIKeyboardCandidateCorrectionDidChangeNotification" 有效但未记录,因此 Apple 是否会拒绝遵守此通知名称的应用程序?
    【解决方案3】:

    我不确定,但您可以尝试使用 addTarget: action: forControlEvents: 的自定义方法。试试UIControlEventAllEditingEvents 选项。

    【讨论】:

    • 不错的尝试,但如果文本字段为空,UIControlEventAllEditingEvents 不会捕获删除。 UIControlEventAllEvents 也没有。
    【解决方案4】:

    好的,我想通了。所以在 - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text 委托方法(即当文本即将被输入时)你只需做一个

    if (text.length <= 0) {
        // backspace
        return FALSE;
    } else {
    

    因为退格 text.length 将 == 0,而其他所有内容将 == 1。

    【讨论】:

    • 是的,你是对的。但是我的问题是关于 UITextField。 UITextFieldDelegate 的 textField:shouldChangeCharactersInRange:replacementString: 当文本字段不包含任何内容时不会被调用。此行为与 UITextView 不同。
    • 所以。使用 UITextView。重写很简单
    • 最有意义+1
    【解决方案5】:

    当使用小键盘时,显然你正在将它写入某个变量(例如:UITextField、UILabel 甚至是全局字符串)

    检测删除操作的选项可以是:

    • 保持全局“int previousLengthOfText”
    • 将此变量初始化为lastLengthOfText = 0;
    • 捕捉委托函数的变化:例如:

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

    • 将你的 label\textField 的长度与这个全局变量进行比较,看看是否添加或删除了一个字符。

    例如:

    if ([self.myTextField.text length] > previousLengthOfText) {
    {
    // user deleted a character - Do your action here
    previousLengthOfText = [self.myTextField.text length];
    }
    

    【讨论】:

      【解决方案6】:

      这似乎可以通过继承 UITextField 来实现。 UITextField 符合一个称为 UITextInput 的协议,而后者又符合另一个称为 UIKeyInput 的协议。 UIKeyInput 协议有一个方法 deleteBackward 每次按下键盘上的退格键时都会触发。

      这是它的样子

      标题

      #import <UIKit/UIKit.h>
      
      @interface EmptyDeleteTextField : UITextField
      
      @end
      

      实施

      - (void)deleteBackward
      {
          NSLog_SM(@"Length: %d", (int)self.text.length);
          [super deleteBackward];
      }
      

      PS:不要忘记调用 super,因为你不想弄乱 UITextField 的默认行为。

      【讨论】:

        【解决方案7】:

        这可以通过继承 UITextField 并将其添加为所需文本字段的自定义类来实现。 然后覆盖方法“deleteBackward” 此方法将捕获所有退格事件。

        Swift 中的代码:

        override func deleteBackward() {
                super.deleteBackward()
                // Enter your stuff here
            }
        

        还要确保你也调用了超级方法,因为它正在执行事件的基本功能。

        【讨论】:

        • 正确答案!
        【解决方案8】:

        我正在为 swift 3 中的更完整示例添加此答案。 基本上,我需要一个 pincode 类型的视图,其中有多个文本字段,每个单元格中允许一个字符。

        像这样 我首先创建了 UITextField 的子类和定义新函数的协议。

        protocol MYDeleteActionTextFieldDelegate {
            func textFieldDidSelectDeleteButton(_ textField: UITextField) -> Void
        }
        class MYDeleteActionTextField: UITextField {
            var deleteDelegate: MYDeleteActionTextFieldDelegate?
            override func deleteBackward() {
                // Need to call this before super or the textfield edit may already be in place
                self.deleteDelegate?.textFieldDidSelectDeleteButton(self)
                super.deleteBackward()
            }
        }
        

        然后您使用新的子类创建文本字段并在您的视图控制器中实现委托。就我而言,我在数组中管理文本字段以方便使用,并使用 PureLayout 布局单元格。我这样存储它们

        var pinFields = UITextField

        然后在viewDidLoad() 中,我将所有引脚字段添加到数组中,如下所示:

        for _ in 1...6 {
                    let field = EDFDeleteActionTextField.init(forAutoLayout: ())
                    field.addTarget(self, action: #selector(textFieldDidChange(textField:)), for: UIControlEvents.editingChanged)
                    field.delegate = self
                    field.deleteDelegate = self
                    field.textAlignment = .center
                    field.font = UIFont.newBigTitle()
                    field.textColor = UIColor.edfBlue()
                    field.backgroundColor = UIColor.edfWhite()
                    self.pinFields.append(field)
                    self.pinView.addSubview(field)
                }
        

        现在您只需要响应所有适当的委托方法和上面添加的textFieldDidChange 目标。

        // MARK: UITextFieldDelegate
            func textFieldDidChange(textField: UITextField) {
                // If the user typed one character, move to the next cell.
                if (textField.text?.characters.count == 1) {
                    let index = pinFields.index(of: textField)
                    textField.resignFirstResponder()
                    if (pinFields.count > index! + 1) {
                        pinFields[index! + 1].becomeFirstResponder()
                    }
                } // If they deleted the character move to previous cell
                else if (textField.text?.characters.count == 0) {
                    let index = pinFields.index(of: textField)
                    if (index! - 1 >= 0) {
                        pinFields[index! - 1].becomeFirstResponder()
                    }
                }
            }
        
            func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
                if range.location > 0 {
                    let index = pinFields.index(of: textField)
                    // If there is already text in the text field and the next cell is empty - move the newly typed character to that cell.
                    if (pinFields.count > index! + 1) {
                        let nextField = pinFields[index! + 1]
                        if (nextField.text?.characters.count == 0) {
                            textField.resignFirstResponder()
                            nextField.becomeFirstResponder()
                            nextField.text = string
                        }
                    }
                    return false
                }
                return true
            }
        
            func textFieldShouldReturn(_ textField: UITextField) -> Bool {
                textField.resignFirstResponder()
                return false
            }
        
            // MARK: EDFDeleteActionTextFieldDelegate
            func textFieldDidSelectDeleteButton(_ textField: UITextField) {
                // If user clicked delete, and there are no characters, move to previous cell if available.
                // If there are characters, it is handled in UITextFieldDelegate
                if (textField.text?.characters.count == 0) {
                    let index = pinFields.index(of: textField)
                    if (index! - 1 >= 0) {
                        pinFields[index! - 1].becomeFirstResponder()
                    }
                    else {
                        textField.resignFirstResponder()
                    }
                }
            }
        

        我将省略无聊的部分(例如布局文本字段等),因为这个通用功能在更多情况下比这个 pincode 视图有用,但是实现这个子类和协议应该提供你需要的所有功能对于类似类型的视图并解决手头的问题(这可能需要类似的东西)。

        编码愉快。

        【讨论】:

          【解决方案9】:

          对于第一季度。

          在下面的 Swift 4.2 中适用于我

          @objc func keyboardInputShouldDelete(_ textField: UITextField) -> Bool {
                  print("User Pressed backspace in empty textfield ")
                  return true
              }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2022-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-12-30
            • 1970-01-01
            • 2014-10-11
            • 1970-01-01
            相关资源
            最近更新 更多