web-dev-qa-db-ja.com

空のUITextFieldでバックスペースを検出

を検出する方法はありますか Backspace/Delete 空のUITextFieldでiPhoneキーボードのキーが押されましたか?いつ知りたい Backspace UITextFieldが空の場合のみ押されます。


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

[[NSNotificationCenter defaultCenter] addObserver:self
          selector:@selector(handleTextFieldChanged:)
              name:UITextFieldTextDidChangeNotification
            object:searchTextField];

この通知は受信されます(handleTextFieldChanged関数が呼び出されます)が、まだ Backspace 空のフィールドのキー。何か案は?


この質問については混乱があるようです。通知を受け取りたいとき Backspace キーが押されました。それでおしまい。ただし、UITextFieldがすでに空の場合も解決策が機能する必要があります。

120
marcc

これは長いショットかもしれませんが、うまくいくかもしれません。テキストフィールドのテキストをゼロ幅のスペース文字に設定してみてください\u200B。空のテキストフィールドでバックスペースが押されると、実際にスペースが削除されます。次に、スペースを再挿入します。

ユーザーがキャレットをスペースの左側に移動すると、機能しない場合があります。

34
Andrew

スウィフト4:


サブクラスUITextField

// MyTextField.Swift
import UIKit

protocol MyTextFieldDelegate {
    func textFieldDidDelete()
}

class MyTextField: UITextField {

    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

ここで、MyTextFieldDelegateUIViewControllerに追加し、UITextFieldsmyDelegateselfに設定するだけです。

//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");
}
140
Jacob Caraballo

更新:-[UITextField deleteBackward]をオーバーライドする例については、 JacobCaraballoの答え を参照してください。

チェックアウト UITextInput 、具体的には UIKeyInput には deleteBackwardデリゲートメソッド thatalwaysは、削除キーが押されると呼び出されます。単純なことをしている場合は、 SimpleTextInput およびこの iPhoneによって行われるように、UILabelをサブクラス化し、UIKeyInputプロトコルに準拠させることを検討してくださいUIKeyInputの例 。 注:UITextInputおよびその関連(UIKeyInputを含む)は、iOS 3.2以降でのみ使用できます。

40
ma11hew28

次のようなコード:

@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」に変更することを忘れないでください

31
Jeffrey Loo

迅速な実装:

import UIKit

protocol PinTexFieldDelegate : 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? PinTexFieldDelegate {
            pinDelegate.didPressBackspace(self)
        }
    }
}
18
Ruud Visser

私は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;
}

Compareの結果が-8であるのは少し奇妙です。たぶんC Programming。しかし、その正しい仕事;)

17

delegateを試してください

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

次に、range.length == 1これは、backspaceがヒットした場合のようです。

10
Niklas Alvaeus

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

目的C:

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

Swift:

func keyboardInputShouldDelete(_ textField: UITextField) -> Bool { return true }
10
Pritesh

Niklas Alvaeusの回答は、同様の問題で私を助けてくれました

特定の文字セットへのエントリを制限していましたが、バックスペースを無視していました。だから私はそれをチェックしたrange.length == 1NSStringをトリミングする前。それが本当なら、文字列を返すだけで、それをトリムしません。下記参照

 - (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);
    }   
 }
8
Ben Call

はい、textFieldが空の場合、以下のメソッドを使用してバックスペースを検出します。

追加する必要がありますITextFieldDelegate

yourTextField.delegate = self (必須)

スイフト:

func keyboardInputShouldDelete(_ textField: UITextField) -> Bool { 
    return true
}

目的C:

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

Jacob's answer に問題がある人のために、テキストフィールドのサブクラスを次のように実装しました。

#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
4
furkan3ayraktar

バックスペースを検出するために私が見つけた最良の使用法は、ユーザーが空のUITextFieldでバックスペースを押したことを検出することです。たとえば、メールアプリに「バブル」受信者がいる場合、UITextFieldでバックスペースを押すと、最後の「バブル」受信者が選択されます。

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

実際には、backspaceUITextFieldを正確にゼロ文字(空)で検出する場合は、super deleteBackwardを呼び出す前にdelegateにメッセージを送信する必要があります。例えば:

#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
3
Sam

IOS 6では、フィールドが空のときを含め、バックスペースが押されたときにUITextFieldでdeleteBackwardメソッドが呼び出されます。そのため、UITextFieldをサブクラス化して、独自のdeleteBackward実装を提供できます(スーパーも呼び出します)。

私はまだiOS 5をサポートしているので、Andrewの答えとこれを組み合わせる必要があります。

2
tracy

:)「バックスペースの検出」というタイトルの場合、UIKeyboardTypeNumberPadを使用します。

今夜も同じ質問に答えます。それを見つけるためのコードは次のとおりです。

- (BOOL)textField:(UITextField *)textField 
        shouldChangeCharactersInRange:(NSRange)range 
        replacementString:(NSString *)string
{
    NSLog([NSString stringWithFormat:@"%d", [string length]]);
}

UIKeyboardTypeNumberPadを使用すると、ユーザーは数値またはバックスペースのみを入力できるため、文字列の長さが0の場合、バックスペースキーである必要があります。

上記が助けになることを願っています。

1
Jason Lee

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

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

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

1
Aaron

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

改善されたフォーマット

1
Anjali Prasad

最もポピュラーな答え には、テキストフィールドが空かどうかを検出する機能がありません。

つまり、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...
        }
    }
}
1
Tim

IOS 8.3ではUITextFieldのサブクラス化が機能せず、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
}
1
joel.d

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

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)
    }
}
1
Hemang