【问题标题】:Detect backspace Event in UITextField检测 UITextField 中的退格事件
【发布时间】:2015-06-12 19:12:38
【问题描述】:

我正在寻找有关如何捕获退格事件的解决方案,大多数 Stack Overflow 答案都在 Objective-C 中,但我需要 Swift 语言。

首先我为 UITextField 设置了委托并将其设置为 self

self.textField.delegate = self;

然后我知道使用shouldChangeCharactersInRange 委托方法来检测是否按下了退格键是所有代码都在Objective-C 中。我需要在 Swift 中使用以下这些方法。

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

【问题讨论】:

  • 你对这个问题的 Swift 方法是什么样的?请。向我们展示您的努力,让我们帮助您解决问题所在。 Stack Overflow 不是代码编写服务。
  • 我也在寻找这个解决方案。如果有人知道请回答。

标签: ios swift cocoa-touch uikit uitextfielddelegate


【解决方案1】:

Swift 5: 根据文本视图委托documentation,如果 shouldChangeTextIn 方法返回的替换文本为空,则用户按下退格按钮。如果范围上限大于范围下限(或范围计数为 1 或更多),则应删除文本。如果范围上限和下限相同(或都等于 0),则没有要删除的文本(长度为 0 的范围将被任何内容替换)。我进行了测试,即使在空文本字段上也会调用它。

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    
    guard text.isEmpty else { return true } // No backspace pressed
    if (range.upperBound > range.lowerBound) {
        print("Backspace pressed")
    } else if (range.upperBound == range.lowerBound) {
        print("Backspace pressed but no text to delete")
        if (textView.text.isEmpty) || (textView.text == nil) {
            print("Text view is empty")
        }
    }
    return true
}

【讨论】:

  • 请edit 并附上引用来源的链接。
【解决方案2】:

斯威夫特 5.3

在某些版本中它发生了变化,现在它说:

当用户删除一个或多个字符时,替换字符串 是空的。

所以回答这个问题:

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
  if string.isEmpty {
    // do something
  }
  return true
}

如果要检测某些字符会被删除

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
  if range.length > 0 {
    // We convert string to NSString instead of NSRange to Range<Int>
    // because NSRange and NSString not counts emoji as one character
    let replacedCharacters = (string as NSString).substring(with: range)
  }
  return true
}

如果您想在空文本字段上检测退格键

class TextField: UITextField {
  var backspaceCalled: (()->())?
  override func deleteBackward() {
    super.deleteBackward()
    backspaceCalled?()
  }
}

旧答案

请不要丢弃您的代码。只需将此扩展程序放在代码中的某个位置即可。

extension String {
  var isBackspace: Bool {
    let char = self.cString(using: String.Encoding.utf8)!
    return strcmp(char, "\\b") == -92
  }
}

然后在你的函数中使用它

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
  if string.isBackspace {
    // do something
  }
  return true
}

【讨论】:

【解决方案3】:

我更喜欢继承UITextField 并覆盖deleteBackward(),因为这比使用shouldChangeCharactersInRange 更可靠:

class MyTextField: UITextField {
    override public func deleteBackward() {
        if text == "" {
             // do something when backspace is tapped/entered in an empty text field
        }
        // do something for every backspace
        super.deleteBackward()
    }
}

shouldChangeCharactersInRange hack 与放置在文本字段中的不可见字符相结合有几个缺点:

  • 连接键盘后,可以将光标放在不可见字符之前,并且不再检测到退格,
  • 用户甚至可以选择那个不可见的字符(在键盘上使用 Shift Arrow 或者甚至通过点击插入符号)并且会对该奇怪的字符感到困惑,
  • 只要只有这个不可见的字符,自动完成栏就会提供奇怪的选择,
  • 具有基于文本字段文本的候选选项的亚洲语言键盘会混淆,
  • placeholder 不再显示,
  • 即使clearButtonMode = .whileEditing 不应该显示清除按钮。

当然,由于需要子类化,覆盖deleteBackward() 有点不方便。但更好的 UX 值得付出努力!

如果子类化是不行的,例如当使用带有嵌入的UITextField 的UISearchBar 时,方法调配也应该没问题。

【讨论】:

  • 谢谢!这么多多余的答案没有回答问题,但你的正确答案在这里:)
  • 在使用具有基于文本字段文本的候选选项的亚洲语言键盘时,隐形字符破解可能会引起其他问题。这个答案应该是公认的答案。
  • 谢谢@Helam,将这方面添加到答案中。
  • @OrtwinGentz 有 UISearchBar 的选项吗?
  • @BogdanBogdanov 正如我在回答中提到的那样,对于 UISearchBar,您可以将嵌入的 deleteBackward() 转换为 UISearchTextField(searchTextField 属性)。
【解决方案4】:

斯威夫特 4.2

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    if let char = string.cString(using: String.Encoding.utf8) {
        let isBackSpace = strcmp(char, "\\b")
        if (isBackSpace == -92) {
            print("Backspace was pressed")
        }
    }
    return true
}

旧的 Swift 版本

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    let  char = string.cStringUsingEncoding(NSUTF8StringEncoding)!
    let isBackSpace = strcmp(char, "\\b")

    if (isBackSpace == -92) {
        println("Backspace was pressed")
    }
    return true
}

【讨论】:

  • 这个委托方法没有被触发。委托在viewDidLoad() 方法中设置。
  • -1:此代码有效,但偶然。 The documentation 指定如果用户删除一个或多个字符,string 将是一个空字符串。
  • @gbk 检查此链接stackoverflow.com/questions/1977934/… 以检测退格,即使 TextField 为空。
  • 这个答案是非常错误的,应该避免。 strcmp 的具体返回值(除了它的符号)是没有意义的。字符串为空,不是\b。
【解决方案5】:

我实现了这个功能:

而在最后一个textFiled为空的情况下,我只想切换到上一个textFiled。我尝试了上述所有答案,但在我的情况下没有人能正常工作。出于某种原因,如果我在 isBackSpace == -92 括号中添加比 print 更多的逻辑,则此方法将停止工作...

对我来说,下面的方法更优雅,效果更佳:

斯威夫特

class YourTextField: UITextField {

    // MARK: Life cycle

    override func awakeFromNib() {
        super.awakeFromNib()
    }

    // MARK: Methods

    override func deleteBackward() {
        super.deleteBackward()

        print("deleteBackward")
    }

}

感谢@LombaX 提供answer

【讨论】:

  • deleteBackward方法中如何访问Controller类的实例元素
【解决方案6】:

斯威夫特 4

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

            let  char = string.cString(using: String.Encoding.utf8)!
            let isBackSpace = strcmp(char, "\\b")

            if isBackSpace == -92 {
                print("Backspace was pressed")
                return false
            }
}

【讨论】:

    【解决方案7】:

    斯威夫特 4

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    
        //MARK:- If Delete button click
        let  char = string.cString(using: String.Encoding.utf8)!
        let isBackSpace = strcmp(char, "\\b")
    
        if (isBackSpace == -92) {
            print("Backspace was pressed")
    
            return true
        }
    }
    

    【讨论】:

      【解决方案8】:

      斯威夫特 4

      我发现使用strcmp 的比较无关紧要。我们甚至不知道strcmp 是如何在幕后运作的。在比较当前字符和\b 时的所有其他答案中,objective-C 中的-8 和Swift 中的-92。我写了这个答案,因为上述解决方案对我不起作用。 (Xcode 版本 9.3 (9E145) 使用 Swift 4.1)

      仅供参考:您实际键入的每个字符都是1 或utf8 Encoding 中的更多元素的数组。退格字符是[0]。你可以试试这个。

      PS:不要忘记将正确的delegates 分配给您的textFields。

      public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
      
          let  char = string.cString(using: String.Encoding.utf8)!
          if (char.elementsEqual([0])) {
              print("Backspace was pressed")
          }
          else {
              print("WHAT DOES THE FOX SAY ?\n")
              print(char)
          }
          return true
      }
      

      【讨论】:

        【解决方案9】:

        Swift 4:如果用户按下退格按钮,字符串为空,因此这种方法强制 textField 只接受来自指定字符集的字符(在本例中为 utf8 字符)和退格键(字符串。 isEmpty 情况)。

        func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
            if string.cString(using: String.Encoding.utf8) != nil {
                return true
            } else if string.isEmpty {
                return true
            } else {
                return false
            }
        }
        

        【讨论】:

          【解决方案10】:

          在 Swift 3 中

          func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
              let  char = string.cString(using: String.Encoding.utf8)!
              let isBackSpace = strcmp(char, "\\b")
          
              if (isBackSpace == -92) {
                   print("Backspace was pressed")
              }
              return true
          }
          

          :)

          【讨论】:

            【解决方案11】:

            如果您需要在空文本字段中检测退格(例如,如果您需要在按退格时自动切换回上一个文本字段),您可以使用建议的方法组合 - 添加不可见符号并使用标准委托方法textField:shouldChangeCharactersInRange:replacementString:喜欢关注

            1. 创建隐形标志

              private struct Constants {
                  static let InvisibleSign = "\u{200B}"
              }
              
            2. 为 textField 设置委托

              textField.delegate = self
              
            3. 在事件 EditingChanged 检查文本,如果需要添加不可见符号,如下所示:

              @IBAction func didChangeEditingInTextField(sender: UITextField) {
                  if var text = sender.text {
                      if text.characters.count == 1 && text != Constants.InvisibleSign {
                          text = Constants.InvisibleSign.stringByAppendingString(text)
                          sender.text = text
                      }
                  }
              }
              

            1. 添加委托方法textField:shouldChangeCharactersInRange:replacementString:的实现

              extension UIViewController : UITextFieldDelegate {
                  // MARK: - UITextFieldDelegate
                  func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
              
                      let  char = string.cStringUsingEncoding(NSUTF8StringEncoding)!
                      let isBackSpace = strcmp(char, "\\b")
              
                      if (isBackSpace == -92) {
                          if var string = textField.text {
                              string = string.stringByReplacingOccurrencesOfString(Constants.InvisibleSign, withString: "")
                              if string.characters.count == 1 {
                                  //last visible character, if needed u can skip replacement and detect once even in empty text field
                                  //for example u can switch to prev textField 
                                  //do stuff here                            
                              }
                          }
                      }
                      return true
                  }
              }
              

            【讨论】:

              【解决方案12】:

              试试这个

              public func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
              
              if(string == "") {
              
                      print("Backspace pressed");
                      return true;
                  }
              }
              

              注意:如果你想允许退格,你可以返回“true”。否则,您可以返回“false”。

              【讨论】:

              • 如果当前文本是文本字段为空会发生什么?
              • 这个代表不会被调用
              • string == "" 最好使用.isEmpty
              • 这就是我要找的,谢谢!也 +1 到.isEmpty。这似乎是比公认的答案更直接的解决方案。
              猜你喜欢
              • 2010-12-30
              • 1970-01-01
              • 1970-01-01
              • 2020-12-11
              • 2011-12-24
              • 2020-09-04
              • 2016-10-31
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多