140

空のiPhoneキーボードでBackspace/キーが押されたことを検出する方法はありますか?が空の場合にのみ、が押されたときを知りたい。DeleteUITextFieldBackspaceUITextField


コメントの@AlexReynoldsからの提案に基づいて、テキストフィールドの作成中に次のコードを追加しました。

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

}

Objective-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をに追加し、myDelegateを次ようUIViewControllerに設定します。UITextFields 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デリゲートメソッドがあります。SimpleTextInputとこのiPhoneUIKeyInputの例で行われているように、単純なことをしている場合は、サブクラス化してプロトコルに準拠させることを検討してください。注:およびその親戚(を含む)は、iOS3.2以降でのみ使用できます。UILabelUIKeyInputUITextInputUIKeyInput

于 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

Swiftの実装:

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

以下のコードを使用してください。テキストフィールドが空の場合でも、キーボードの削除キーを検出するのに役立ちます。

Objective C:

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

Swift:

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
}

Objective 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押すと、最後の「バブル」受信者が選択されます。

これは、ジェイコブ・カラバロの答えと同様の方法で行うことができます。しかし、ジェイコブの答えでは、UITextFieldバックスペースを押したときに1文字残っている場合、デリゲートメッセージを受信するまでに、UITextFieldはすでに空になっているためbackspace、最大1文字のテキストフィールドで効果的に検出できます。

実際、文字がまったくない(空の)を検出する場合backspaceは、への呼び出しUITextFieldの前にメッセージをに送信する必要があります。例えば:delegatesuper 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も呼び出します)。

私はまだiOS5をサポートしているので、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

テキストフィールドに何が表示されるかを事前に構築したり、shouldChangeCharactersInRangeメソッドに入力された特殊文字を把握したりするのではなく、次のことを行うことをお勧めします。

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

これにより、現在の操作が完了した直後にメソッドを呼び出すことができます。これのすばらしい点は、完了するまでに、変更された値がすでにに含まれていることUITextFieldです。その時点で、その長さを確認したり、そこにあるものに基づいて検証したりできます。

于 2012-12-04T20:19:49.790 に答える
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

UITextFieldのサブクラス化はiOS8.3では機能しませんでした。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

ユーザーがバックスペースをタップしているときにテキストフィールドに値がある場合は、マイナーな改善を加えて同様のソリューションを実装しました。これは、バックスペースが押されたときにテキストフィールドが空の場合にのみ、別のテキストフィールドにフォーカスする必要がある場合に役立ちます。

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 に答える
1

最も人気のある答えは、テキストフィールドが空であるかどうかを検出する機能という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

Swift 5.1の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 に答える
0

すべての答えは非常に役に立ち、なぜ誰もがプロトコルルートを取っているのかわかりません。次のようなコールバック関数を使用すると、はるかに少ないコードでそれを行うことができます-

Swift5.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次のようにします-

    class MyViewController:UIViewController {@IBOutlet weak 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];  
}

もちろん、ハッシュは1文字の文字列用です。

于 2012-08-02T03:25:41.430 に答える
-2

TextField Delegateメソッドの使用:

- (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になり、空の文字列オブジェクトがその1文字に置き換わります。」

于 2013-03-30T06:59:07.990 に答える
-4

シンプルに保つために、ここで確認する必要がある唯一の条件です

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