web-dev-qa-db-ja.com

iOS 8のUITextFieldで削除キーを検出する方法は?

UITextFieldをサブクラス化し、UIKeyInputプロトコルのdeleteBackwardメソッドを実装して、押されているバックスペースを検出しました。これはiOS 7では正常に機能しますが、iOS 8では機能しません。

backspaceキーを押すと、UITextFieldでdeleteBackwardが呼び出されなくなりました。

ドキュメントとリリースノートを確認しましたが、これが発生する理由については何も指摘していません。ポインタはありますか?

37
VNVN

Githubで MBContactPicker の例を確認する必要があります。私がテストしたiOS8のBackspaceボタンを介したMBContactPickerでの連絡先の削除。そして、それは大いに働きます!例として使用できます。

MBContactPickerの作成者はnextメソッドを使用します。UITextFieldを空にする必要がある場合(または空の場合は、becomeFirstResponderを呼び出す前)、単一の空白記号をそこに保存します。そして、Backspaceボタンを押すと(フォーカスがUITextFieldのテキストの終わりに設定されたとき)、method

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

働くでしょう。その中で、次のようなチェックを使用する必要があります。

NSString *resultString = [textField.text stringByReplacingCharactersInRange:range withString:string];
BOOL isPressedBackspaceAfterSingleSpaceSymbol = [string isEqualToString:@""] && [resultString isEqualToString:@""] && range.location == 0 && range.length == 1;
if (isPressedBackspaceAfterSingleSpaceSymbol) {
    //  your actions for deleteBackward actions
}

したがって、UITextFieldに単一の空白が含まれることを常に制御する必要があります。

これはハックではありません。そのため、ユーザーは一部の動作が変更されたことに気付かないでしょう

12
iVader

多くの人がこれはバグだと言っていますが、この問題はGM私のアプリ用にこのコードを書き、iOS 7-8でテストしました。

次のメソッドをUITextFieldサブクラスに追加します。

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

    BOOL isIos8 = ([[[UIDevice currentDevice] systemVersion] intValue] == 8);
    BOOL isLessThanIos8_3 = ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.3f);

    if (![textField.text length] && isIos8 && isLessThanIos8_3) {
        [self deleteBackward];
    }

    return shouldDelete;
}

このコードは、プライベートAPIの赤い線の少し前ですが、使用する際に問題はないはずです。このコードのアプリはアプリストアにあります。

少し説明するために、このメソッドのスーパー実装を呼び出して、コードが失われないようにしました。テキストがなく、iOSバージョンが8〜8.2の場合、-deleteBackwardを呼び出します。

[〜#〜] edit [〜#〜]:1/22/15

サブクラス化されたUITextField-deleteBackwardメソッドをサブクラス化することも役立ちます。これにより、いくつかの条件付きバグが修正されます。 1つは、カスタムキーボードを使用する場合です。メソッドの例を次に示します。

- (void)deleteBackward {
    BOOL shouldDismiss = [self.text length] == 0;

    [super deleteBackward];

    if (shouldDismiss) {
        if ([self.delegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)]) {
            [self.delegate textField:self shouldChangeCharactersInRange:NSMakeRange(0, 0) replacementString:@""];
        }
    }
}

[〜#〜] edit [〜#〜]:4/13/15

@ Gee.Eがコメントしたように、iOS 8.3はこの問題を修正しました。変更が反映されるようにコードが更新されました。

47
cnotethegr8

UITextFieldデリゲートメソッドを実装することにより、ユーザーがバックスペースを使用してテキストを削除したことを検出できます。

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (range.length==1 && string.length==0)
        NSLog(@"backspace tapped");

    return YES;
}
22
almas

Swift 2.2:

func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {

    if text == "" {
      print("Backspace has been pressed")
    }

    return true
}
5

IOS8では、一部のカスタムキーボードはWord全体を削除するため、string.lengthのみを確認してください。

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (string.length==0) { //Delete any cases
       if(range.length > 1){
          //Delete whole Word
       }
       else if(range.length == 1){
          //Delete single letter
       }
       else if(range.length == 0){
          //Tap delete key when textField empty
       }  
    }  
    return YES;
}
5
LE SANG

これは元の質問に明示的に答えているわけではありませんが、textField(_:shouldChangeCharactersIn:replacementString:)のドキュメントにあるような価値はありません。

"string:指定された範囲の置換文字列。入力中、このパラメータには通常、入力された新しい文字が1つだけ含まれますが、ユーザーがテキストを貼り付ける場合はさらに文字が含まれます。以上の文字の場合、置換文字列は空です。」

したがって、textField(_:shouldChangeCharactersIn:replacementString:)を実装し、UITextFieldDelegateの長さが0かどうかを確認すると、string内のバックスペースを検出できます。

ここでの他の多くの答えは、ドキュメントを参照せずにこの同じロジックを使用しているため、ソースから適切に取得することで、より快適に使用できるようになります。

2
Brian Sachetta

BackSpaceベースの削除を検出するためのSwift 2.0バージョン、 almasからのコード投稿を参照

//For Detecting Backspace based Deletion of Entire Word in TextField
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { 
    if (range.length == 1 && string.isEmpty){
        print("Used Backspace")
    }
return true
}
1
Abhijeet

スイフト2:

if (string.characters.count == 0 && range.length == 1) {
            return true
}

このように使用する必要がありますstring.characters.count

0
fatihyildizhan
- (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;

}

基本的に、このメソッドは、どのボタンを押している(または押したばかりの)ボタンを検出します。この入力はNSStringとして入力されます。このNSStringをC char型に変換してから、従来のバックスペース文字(\ b)と比較します。このstrcmpが-8に等しい場合、バックスペースとして検出できます。

0
mars