簡體   English   中英

檢測 UITextField 中的退格事件

[英]Detect backspace Event in UITextField

我正在尋找有關如何捕獲退格事件的解決方案,大多數 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;
}

斯威夫特 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
}

我更喜歡deleteBackward() 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 讓它值得付出努力!

如果子類化是UISearchBar ,例如,當使用UISearchBar及其嵌入的UITextField ,方法混合也應該沒問題。

斯威夫特 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
}

如果你想在空的 textField 上檢測退格

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

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
}

:)

嘗試這個

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

if(string == "") {

        print("Backspace pressed");
        return true;
    }
}

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

如果您需要在空的 textField 中檢測退格(例如,如果您需要在按下退格鍵時自動切換回上一個 textField),您可以使用建議的方法組合 - 添加不可見符號並使用標准委托方法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 } }

我實現了這個功能:

在此處輸入圖片說明

而在最后一個 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 的回答

斯威夫特 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
            }
}

斯威夫特 4

我發現使用strcmp的比較無關緊要。 我們甚至不知道strcmp在幕后是如何運作的。在比較當前 char 和\\b所有其他答案中,objective-C 中的結果為-8 ,Swift 中的結果為-92 我寫這個答案是因為上述解決方案對我不起作用。 (使用 Swift 4.1 Xcode 版本9.3 (9E145)

僅供參考:您實際鍵入的每個字符都是utf8 Encoding1或多個元素的數組。 退格字符是[0] 你可以試試這個。

PS:不要忘記為您的textFields分配適當的delegates

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
}

斯威夫特 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
    }
}

Swift 4:如果用戶按下退格按鈕,則字符串為空,因此此方法強制 textField 僅接受來自指定字符集(在本例中為 utf8 字符)和退格(string.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
    }
}

Swift 5:根據文本視圖委托文檔,如果 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
}

我來這里是為了尋找如何檢測刪除的答案。 我想知道用戶點擊后 UITextView 何時為空delete 在測試時,我意識到我還需要捕獲整個單詞的刪除和刪減。 這是我想出的答案。

extension SomeViewController: UITextViewDelegate {
    
    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        
        let deleteTapped = text == ""
        let cursorAtBeginning = range.location == 0
        let deletedCharactersEqualToTextViewCount = range.length == textView.text.count

        let everythingWasDeleted = deleteTapped && cursorAtBeginning && deletedCharactersEqualToTextViewCount
        if everythingWasDeleted {
            // Handle newly empty view from deletion
        } else {
            // Handle other situation
        }
            
        return true
    }
}

感謝之前所有有用的答案。 我希望這可以幫助別人。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM