web-dev-qa-db-ja.com

UITextFieldでバックスペースイベントを検出する

バックスペースイベントをキャプチャする方法に関するソリューションを探しています。ほとんどのStack Overflowの回答はObjective-Cにありますが、Swift language。

最初に、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;
}
28
Want Query

Swift 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
}
63
Long Pham

In Swift

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
}

:)

18
Insou

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ハックとテキストフィールドに配置された不可視文字との組み合わせには、いくつかの欠点があります。

  • キーボードを接続すると、不可視文字の前にカーソルを置くことができ、バックスペースが検出されなくなります。
  • ユーザーはその不可視文字を選択することもでき(キーボードで_Shift Arrow_を使用するか、キャレットをタップすることもできます)、その奇妙な文字について混乱します。
  • オートコンプリートバーは、この目に見えないキャラクターだけがある限り、奇妙な選択肢を提供します。
  • テキストフィールドのテキストに基づいた候補オプションがあるアジア言語キーボードは混同されますが、
  • placeholderは表示されなくなり、
  • _clearButtonMode = .whileEditing_を使用する必要がない場合でも、クリアボタンが表示されます。

もちろん、deleteBackward()のオーバーライドは、サブクラス化が必要なため、少し不便です。しかし、より良いUXは努力する価値があります!

そして、サブクラス化が禁止されている場合、例えば埋め込みUISearchBarUITextFieldを使用する場合、メソッドのスウィズルも問題ないはずです。

16
Ortwin Gentz

空のtextFieldでもバックスペースを検出する必要がある場合(たとえば、BackSpaceを押すとprev 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
            }
        }
    }
    

enter image description here

  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
        }
    }
    
11
gbk

これを試して

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

if(string == "") {

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

注:バックスペースを許可する場合は、「true」を返すことができます。それ以外の場合は、「false」を返すことができます。

7
Augustine P A

スイフト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
            }
}
5
Amr Angry

スイフト4

strcmpを使用して比較は無関係です。 strcmpが内部でどのように動作しているかさえわかりません。現在のcharと\bを比較する他のすべての答えは、objective-Cの-8とSwiftの-92です。上記の解決策がうまくいかなかったので、私はこの答えを書きました。 (Xcodeバージョン9.3 (9E145) using Swift 4.1

FYI:実際に入力するすべての文字は、1utf8 Encodingまたはそれ以上の要素の配列です。 backSpace文字は[0]です。これを試すことができます。

PS:適切なdelegatestextFieldsに割り当てることを忘れないでください。

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
GreenCamper

コードをゴミ箱に捨てないでください。この拡張機能をコードのどこかに配置するだけです。 (Swift 4.1)

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
}
4
Dmitry Kozlov

この機能を実装しました。

enter image description here

最後のtextFiledが空の場合、前のtextFiledに切り替えたいだけです。上記の答えをすべて試しましたが、私の状況では誰もうまくいきません。何らかの理由で、isBackSpace == -92括弧ブロックにprintより多くのロジックを追加すると、このメソッドは動作を停止しました...

私に関しては、以下の方法はよりエレガントで魅力的なものです:

Swift

class YourTextField: UITextField {

    // MARK: Life cycle

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

    // MARK: Methods

    override func deleteBackward() {
        super.deleteBackward()

        print("deleteBackward")
    }

}

answer をありがとう@LombaX

3
Roman Romanenko

スイフト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
    }
}
1
Shakeel Ahmed

Swift 4:ユーザーがバックスペースボタンを押すと、文字列が空になるため、このアプローチでは、指定された文字セット(この場合は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
    }
}
1
Nimz