Android EditText delete(backspace)キーイベント


122

editTextの削除(バックスペース)キーイベントを検出するにはどうすればよいですか?TextWatcherを使用してみましたが、editTextが空の場合、削除キーを押しても何も起こりません。テキストがない場合でも、editTextのeditTextを検出したいのですが。

回答:


172

注:onKeyListenerソフトキーボードでは機能しません。

キーを押すことを検出できるように設定OnKeyListenerすることeditTextができます
編集:私たちがチェックKeyEvent.KEYCODE_BACKしているよくある間違いですbackspaceが、実際にはそうですKeyEvent.KEYCODE_DEL(本当にその名前は非常に混乱しています!)

editText.setOnKeyListener(new OnKeyListener() {                 
    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {
        //You can identify which key pressed buy checking keyCode value with KeyEvent.KEYCODE_
        if(keyCode == KeyEvent.KEYCODE_DEL) {  
            //this is for backspace
        }
        return false;       
    }
});

9
私は試してみましたが、onKeyListenersはバックスペースを登録しないようです。
11

3
ソフトキーボードでは機能しません。これはハードウェア入力に対してのみ機能します。
Varundroid、2014

6
私のNexus4(KitKatを実行している)では、これソフトウェアキーボードで機能します。
Matthias

10
SOがソフトキーで機能しない場合、なぜこの回答がAndroidプラットフォーム内/下で受け入れられるのですか
DJphy

32
event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_DELバックスペースのプレスごとに2回イベントを発生させたくない場合に使用します
Fonix

83

質問して久しぶりですが、同じ問題が発生しました。Estelがすでに述べたように、キーリスナーの問題は、ハードウェアキーボードでしか機能しないことです。IME(ソフトキーボード)でこれを行うには、解決策はもう少し複雑です。

実際にオーバーライドする単一のメソッドはsendKeyEventEditTextInputConnectionクラスにあります。このメソッドは、IMEでキーイベントが発生したときに呼び出されます。しかし、EditTextこれをオーバーライドするには、onCreateInputConnectionメソッドをオーバーライドするカスタムを実装し、デフォルトInputConnectionオブジェクトをプロキシクラスでラップする必要があります。:|

複雑に聞こえますが、ここで私が考案した最も簡単な例を示します。

public class ZanyEditText extends EditText {

    private Random r = new Random();

    public ZanyEditText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public ZanyEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ZanyEditText(Context context) {
        super(context);
    }

    public void setRandomBackgroundColor() {
        setBackgroundColor(Color.rgb(r.nextInt(256), r.nextInt(256), r
                .nextInt(256)));
    }

    @Override
    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
        return new ZanyInputConnection(super.onCreateInputConnection(outAttrs),
                true);
    }

    private class ZanyInputConnection extends InputConnectionWrapper {

        public ZanyInputConnection(InputConnection target, boolean mutable) {
            super(target, mutable);
        }

        @Override
        public boolean sendKeyEvent(KeyEvent event) {
            if (event.getAction() == KeyEvent.ACTION_DOWN
                    && event.getKeyCode() == KeyEvent.KEYCODE_DEL) {
                ZanyEditText.this.setRandomBackgroundColor();
                // Un-comment if you wish to cancel the backspace:
                // return false;
            }
            return super.sendKeyEvent(event);
        }

    }

}

呼び出し先の行setRandomBackgroundColorは、特別なバックスペースアクションが発生する場所です。この場合、EditTextの背景色を変更します。

XMLからこれを拡張する場合は、タグとして完全なパッケージ名を使用することを忘れないでください。

<cc.buttfu.test.ZanyEditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/somefield"
></cc.buttfu.test.ZanyEditText>

27
最近、ジェリービーンで同じ問題に遭遇しました。sendKeyEvent(...)の代わりにdeleteSurroundingText(...)をオーバーライドする必要があったことを除いて、このソリューションはほとんど機能することがわかりました(これはまったく呼び出されていませんでした)。これが誰かを助けることを願っています!
ブランドン

この回答と上記の@Brandonのコメントを組み合わせると、これがうまくいきました。私が今疑問に思っているのは、これがJellyBean以前のデバイスでどのように機能するかです。
クリストファーペリー

2.2と2.3のデバイスで受け入れられている回答で動作します。
クリストフ

2.3で2回バックスペースのキーイベントを発生させているようです...:/
Jeff

25
edittextが空の場合、これは機能しません。edittextが空でテキストがない場合に、deleteキーのイベントを取得する方法に関するアイデアはありますか?4.2
Rickster 2014

69

これはイドリスの答えへの追加であり、オーバーライドにdeleteSurroundingTextも追加しています。詳細については、こちらをご覧ください:Android:WebView / BaseInputConnectionのバックスペース

package com.elavon.virtualmerchantmobile.utils;

import java.util.Random;

import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputConnectionWrapper;
import android.widget.EditText;

public class ZanyEditText extends EditText {

    private Random r = new Random();

    public ZanyEditText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public ZanyEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ZanyEditText(Context context) {
        super(context);
    }

    public void setRandomBackgroundColor() {
        setBackgroundColor(Color.rgb(r.nextInt(256), r.nextInt(256), r
                .nextInt(256)));
    }

    @Override
    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
        return new ZanyInputConnection(super.onCreateInputConnection(outAttrs),
                true);
    }

    private class ZanyInputConnection extends InputConnectionWrapper {

        public ZanyInputConnection(InputConnection target, boolean mutable) {
            super(target, mutable);
        }

        @Override
        public boolean sendKeyEvent(KeyEvent event) {
            if (event.getAction() == KeyEvent.ACTION_DOWN
                    && event.getKeyCode() == KeyEvent.KEYCODE_DEL) {
                ZanyEditText.this.setRandomBackgroundColor();
                // Un-comment if you wish to cancel the backspace:
                // return false;
            }
            return super.sendKeyEvent(event);
        }


        @Override
        public boolean deleteSurroundingText(int beforeLength, int afterLength) {       
            // magic: in latest Android, deleteSurroundingText(1, 0) will be called for backspace
            if (beforeLength == 1 && afterLength == 0) {
                // backspace
                return sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL))
                    && sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL));
            }

            return super.deleteSurroundingText(beforeLength, afterLength);
        }

    }

}

3
ありがとうございました!deleteSurroundingText他の無数のソリューションを試した後、ビットはまさに私が必要としたものでした。
Adam Rosenfield 2013

5
このソリューションは、以前のAndroidバージョンでは本当にうまく機能しましたが、残念ながら、deleteSurroundingTextは、4.4(KitKat)で空白を削除するときにのみ呼び出されます。私はNexus4と7の両方でテストしました
Dean

1
EditTextが複数行の場合、deleteSurroundingTextが必要なようです。奇妙な
アレックスSorokoletov 14

7
トンの人に感謝し、deleteSurroundTextを使用して動作しませんでした。Androidは非常にランダムなので、名前をandromに変更する必要があります。
Torsten Ojaperv

2
うまくいきましたが、句読点やスペースはもう削除できません!
jaytj95

29

これが私のすべてのAPIで機能する簡単なソリューションです。

private int previousLength;
private boolean backSpace;

// ...

@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    previousLength = s.length();
}

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}

@Override
public void afterTextChanged(Editable s) {
    backSpace = previousLength > s.length();

    if (backSpace) {

        // do your stuff ...

    } 
}

アップデート17.04.18
コメントで指摘されているように、EditTextが空の場合、このソリューションはバックスペースプレスを追跡しません(他のほとんどのソリューションと同じ)。
ただし、ほとんどのユースケースではこれで十分です。
PSもし私が今日同様のものを作成しなければならなかったら、私はそうするでしょう:

public abstract class TextWatcherExtended implements TextWatcher {

    private int lastLength;

    public abstract void afterTextChanged(Editable s, boolean backSpace);

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        lastLength = s.length();
    }

    @Override
    public void afterTextChanged(Editable s) {
        afterTextChanged(s, lastLength > s.length());
    }  
}

次に、それを通常のTextWatcherとして使用します。

 editText.addTextChangedListener(new TextWatcherExtended() {
        @Override
        public void afterTextChanged(Editable s, boolean backSpace) {
           // Here you are! You got missing "backSpace" flag
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            // Do something useful if you wish.
            // Or override it in TextWatcherExtended class if want to avoid it here 
        }
    });

ちょうど私が必要なもの!ありがとうございました!
DH28

9
TextWatcherが空のEditTextでトリガーされない
Dan Neacșu

@Leo Droidcoder同様のソリューションで使用しました。明確、簡潔、そして完璧に動作します...乾杯。
AJW 2017

このアルゴリズムには、入力後にスペースをクリックするかのように欠陥があり、以前の長さがs.lengthよりも長い
Marcin S.

2
選択を使用しない限り機能します(オートコンプリート)
Javatar

13

解決策を見つけるために2日間送信し、実際に機能するものを見つけました:)(ソフトキーについて)

public TextWatcher textWatcher = new TextWatcher() {
@Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {   } 

@Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        if (count == 0) {
        //Put your code here.
        //Runs when delete/backspace pressed on soft key (tested on htc m8)
        //You can use EditText.getText().length() to make if statements here
        }
    }

@Override
    public void afterTextChanged(Editable s) {
    }
}

EditWatchにtextwatcherを追加した後:

yourEditText.addTextChangedListener(textWatcher);

他のAndroidデバイス(samsung、LGなど)でも動作することを願っています。


デバイスHTCの欲望(HTCが:-Pかかわらず共通である)
Junaid

入力されたものが空白である場合、カウントも== 0
Bincy Baby

Brilliant no 1 answer bro :)
Gundu Bandgar

6
それは完全に機能しません。count == 0は、edittextが空の場合のみです!
Leo Droidcoder、

@MarcAlexanderこの答えについてはわかりませんが、私の答えは上記の答えで確認できます
Leo Droidcoder

5

完璧に機能する私のシンプルなソリューション。フラグを追加する必要があります。私のコードスニペット:

editText.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            if (after < count) {
                isBackspaceClicked = true;
            } else {
                isBackspaceClicked = false;
            }
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) { }

        @Override
        public void afterTextChanged(Editable s) {
            if (!isBackspaceClicked) {
                // Your current code
            } else {
                // Your "backspace" handling
            }
        }

textChangeListnerがemptTextviewで呼び出されることはありません。
Janardhan R

3

TextWatcherでEditTextを作成する例

EditText someEdit=new EditText(this);
//create TextWatcher for our EditText
TextWatcher1 TW1 = new TextWatcher1(someEdit);
//apply our TextWatcher to EditText
        someEdit.addTextChangedListener(TW1);

カスタムTextWatcher

public class TextWatcher1 implements TextWatcher {
        public EditText editText;
//constructor
        public TextWatcher1(EditText et){
            super();
            editText = et;
//Code for monitoring keystrokes
            editText.setOnKeyListener(new View.OnKeyListener() {
                @Override
                public boolean onKey(View v, int keyCode, KeyEvent event) {
                    if(keyCode == KeyEvent.KEYCODE_DEL){
                        editText.setText("");
                    }
                        return false;
                }
            });
        }
//Some manipulation with text
        public void afterTextChanged(Editable s) {
            if(editText.getText().length() == 12){
                editText.setText(editText.getText().delete(editText.getText().length() - 1, editText.getText().length()));
                editText.setSelection(editText.getText().toString().length());
            }
            if (editText.getText().length()==2||editText.getText().length()==5||editText.getText().length()==8){
                editText.setText(editText.getText()+"/");
                editText.setSelection(editText.getText().toString().length());
            }
        }
        public void beforeTextChanged(CharSequence s, int start, int count, int after){
        }
        public void onTextChanged(CharSequence s, int start, int before, int count) {



        }
    }

1

Kotlinを使用している人のために

addOnTextChanged 一部のケースを処理するのに十分な柔軟性がない(例:編集テキストが空のときにユーザーが削除を押したかどうかを検出する)

setOnkeyListenerソフトキーボードやハードキーボードでも機能しました!しかし、いくつかのデバイス上で。私の場合、Samsung s8では機能しますが、Xiaomi mi8 seでは機能しません。

kotlinを使用している場合は、crossline関数を使用できますdoOnTextChanged。これは同じaddOnTextChangedですが、編集テキストが空の場合でもコールバックがトリガーされます。

注:doOnTextChangedはAndroid KTXライブラリの一部です


2
あなたはおそらくdoOnTextChanged 拡張機能がAndroid KTXライブラリでアクセス可能であることを指定するかもしれません

2
しかし、コールバックは「編集テキストが空でもトリガーされない」ようです。空のdelete(backspace)インターセプトを含むスニペットを提供していただけEditTextませんか?事前の感謝

1
ああ、私はプロジェクトを開発するときにそれをテストしています。私の場合、xiaomi mi8seを使用しています。edittextが空でDeleteキーを押すと、コールバックは発生しません。この文のスニペットを検索します。
Mạnhホアンフイン

0

Stackoverflowにも同様の質問があります。メソッドを含むオブジェクトEditTextにアクセスするには、オーバーライドする必要があります。削除(バックスペース)イベントを検出するのに役立ちます。Androidで提供した解決策をご覧ください。バックスペースをキャプチャできません。ソフトでプレスを削除できません。キーボードInputConnectiondeleteSurroundingText


0

これは私のために働いているようです:

public void onTextChanged(CharSequence s, int start, int before, int count) {
    if (before - count == 1) {
        onBackSpace();
    } else if (s.subSequence(start, start + count).toString().equals("\n")) {
        onNewLine();
    }
}

0

Dialogでも同じ問題に直面しています。setOnKeyListenerを使用しているためです。しかし、デフォルトの戻り値をtrueに設定しています。以下のコードのような変更の後、それは私にとってはうまくいきます。

    mDialog.setOnKeyListener(new Dialog.OnKeyListener() {

        @Override
        public boolean onKey(DialogInterface arg0, int keyCode,
                             KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_BACK) {
                mDialog.dismiss();
                return true;
            }
            return false;//this line is important 

        }
    });

0

@Jiffに基づいて、ZanyEditTextここにあるWiseEditTextsetSoftKeyListener(OnKeyListener)

package com.locopixel.seagame.ui.custom;

import java.util.Random;

import android.content.Context;
import android.graphics.Color;
import android.support.v7.widget.AppCompatEditText;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputConnectionWrapper;

public class WiseEditText extends AppCompatEditText {

    private Random r = new Random();
    private OnKeyListener keyListener;

    public WiseEditText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public WiseEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public WiseEditText(Context context) {
        super(context);
    }

    @Override
    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
        return new MyInputConnection(super.onCreateInputConnection(outAttrs),
                true);
    }

    private class MyInputConnection extends InputConnectionWrapper {

        public MyInputConnection(InputConnection target, boolean mutable) {
            super(target, mutable);
        }

        @Override
        public boolean sendKeyEvent(KeyEvent event) {
            if (keyListener != null) {
                keyListener.onKey(WiseEditText.this,event.getKeyCode(),event);
            }
            return super.sendKeyEvent(event);
        }

        @Override
        public boolean deleteSurroundingText(int beforeLength, int afterLength) {       
            // magic: in latest Android, deleteSurroundingText(1, 0) will be called for backspace
            if (beforeLength == 1 && afterLength == 0) {
                // backspace
                return sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL))
                    && sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL));
            }

            return super.deleteSurroundingText(beforeLength, afterLength);
        }

    }

    public void setSoftKeyListener(OnKeyListener listener){
        keyListener = listener;
    }

}

キー削除イベントごとに2回呼び出されます。
Pankaj Kumar

0

私の問題は、私がカスタムを持っていたTextwatcherので、に追加OnKeyListenerしたくなかったし、EditTextカスタムを作成したくなかったということでしたEditTextafterTextChangedメソッドでバックスペースが押されたかどうかを検出したかったので、イベントをトリガーしないでください。

これは私がこれを解決した方法です。それが誰かのために役立つことを願っています。

public class CustomTextWatcher extends AfterTextChangedTextWatcher {

private boolean backspacePressed;

@Override
public void afterTextChanged(Editable s) {
    if (!backspacePressed) {
        triggerYourEvent();
    }
}

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
    super.onTextChanged(s, start, before, count);
    backspacePressed = count == 0; //if count == 0, backspace is pressed
}
}

0

@Jeffのソリューションをバージョン4.2、4.4、6.0でテストしました。4.2と6.0では、うまく動作します。しかし、4.4では機能しません。

この問題を回避する簡単な方法を見つけました。重要な点は、最初にEditTextのコンテンツに非表示の文字を挿入し、ユーザーがこの文字の前にカーソルを移動できないようにすることです。私の方法は、幅がゼロのImageSpanを含む空白文字を挿入することです。これが私のコードです。

                @Override
                public void afterTextChanged(Editable s) {
                    String ss = s.toString();
                    if (!ss.startsWith(" ")) {
                        int selection = holder.editText.getSelectionEnd();
                        s.insert(0, " ");
                        ss = s.toString();
                        holder.editText.setSelection(selection + 1);
                    }
                    if (ss.startsWith(" ")) {
                        ImageSpan[] spans = s.getSpans(0, 1, ImageSpan.class);
                        if (spans == null || spans.length == 0) {
                            s.setSpan(new ImageSpan(getResources().getDrawable(R.drawable.zero_wdith_drawable)), 0 , 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                        }
                    }
                }

そして、SelectionChangeListenerを持つカスタムEditTextが必要です。

public class EditTextSelectable extends android.support.v7.widget.AppCompatEditText {
public interface OnSelectChangeListener {
    void onSelectChange(int start, int end);
}

private OnSelectChangeListener mListener;

public void setListener(OnSelectChangeListener listener) {
    mListener = listener;
}

...constructors...

@Override
protected void onSelectionChanged(int selStart, int selEnd) {
    if (mListener != null) {
        mListener.onSelectChange(selStart, selEnd);
    }
    super.onSelectionChanged(selStart, selEnd);
}

}

そして最後のステップ

holder.editText.setListener(new EditTextSelectable.OnSelectChangeListener() {
                @Override
                public void onSelectChange(int start, int end) {
                    if (start == 0 && holder.editText.getText().length() != 0) {
                        holder.editText.setSelection(1, Math.max(1, end));
                    }
                }
            });

これで完了です。EditTextに実際のコンテンツがなく、ユーザーが私たちのトリックについて何も知らないときに、バックスペースキーイベントを検出できます。


0

この質問は古いかもしれませんが、答えはTextWatcherを使用して本当に簡単です。

int lastSize=0;
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
    //2. compare the old length of the text with the new one
    //3. if the length is shorter, then backspace was clicked
    if (lastSize > charSequence.length()) {
        //4. Backspace was clicked
        //5. perform action
    }
    //1. get the current length of of the text
    lastSize = charSequence.length();
}

以前のソリューションと同様に、これはオートコンプリート/提案によってトリガーできます。
Stonz2

0

ソフトキーボードで動作する本当にシンプルなソリューションを見つけました。

override fun onTextChanged(text: CharSequence?, start: Int, before: Int, count: Int) {
    text?.let { 
        if(count < before) {
            Toast.makeText(context, "backspace pressed", Toast.LENGTH_SHORT).show()
            // implement your own code
        }
    }
}

-3

アクティビティにキーリスナーを設定し、コールバックメソッドで、ユーザーがヒットしたキーを検出できます。以下のコードは参照用です。それが役に立てば幸い。

//after user hits keys, this method would be called.
public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (editText.isFocused()) {
            switch (keyCode) {
            case KeyEvent.KEYCODE_DEL:  //delete key
                Log.i("INFO", "delete key hit"); //you should see this log in ddms after you hit delete key
                break;
            }
        }
        return super.onKeyUp(keyCode, event);
    }

この解決策を確認しました-KEYCODE_DELは、編集テキストがこれだけでは処理できない場合にのみ、アクティビティにスローされます。たとえば、editTextにテキストがない場合、またはテキストはあるがカーソルが非常に最初にある場合などです。私の場合、まさにその振る舞いが必要なのは面白いことです
アントン・キゼマ

私の活動ではE​​ditTextはなく、キーボードをプログラムで表示させるだけです。すべてのソフトキーボードのキーをキャッチする必要があります。これが唯一の有効な解決策のようです。もう1つは、dispatchKeyEventメソッドをオーバーライドしています。残念ながら、JellyBeanから開始すると、IMEはDELETEキーのKeyEventを送信しません。 developer.android.com/reference/android/view/KeyEvent.html
Bemipefe
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.