web-dev-qa-db-ja.com

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

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

108
Buda Gavril

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

OnKeyListenereditTextに設定すると、キーの押下を検出できます
編集:KeyEvent.KEYCODE_BACKbackspaceでチェックしている一般的な間違いですが、実際は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;       
    }
});
139

あなたが尋ねてからしばらく経ちましたが、私は同じ問題を抱えていました。 Estelで既に述べたように、キーリスナーの問題は、ハードウェアキーボードでのみ機能することです。 IME(ソフトキーボード)でこれを行うには、解決策がもう少し複雑です。

実際にオーバーライドしたいメソッドは、sendKeyEventEditTextクラスのInputConnectionです。このメソッドは、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>
81
Idris

これは、イドリスの答えへの単なる追加であり、deleteSurroundingTextへのオーバーライドも追加します。私はここで詳細を見つけました: Android:WebView/BaseInputConnectionのBackspace

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

    }

}
64
Jeff

すべての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 ...

    } 
}

PDATE 17.04.18
コメントで指摘されているように、EditTextが空の場合、このソリューションはバックスペースプレスを追跡しません(他のほとんどのソリューションと同じです)。
ただし、ほとんどのユースケースではこれで十分です。
P.S。今日似たようなものを作成する必要がある場合は、次のようにします

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 
        }
    });
25
Leo Droidcoder

私は解決策を見つけるために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) {
    }
}

テキストウォッチャーをEditTextに追加した後:

yourEditText.addTextChangedListener(textWatcher);

別のAndroidデバイス(サムスン、LGなど)でも機能することを願っています。

13
J.P

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) {



        }
    }
3
Alex Bigalo

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

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
            }
        }
2
EAMax

バージョン4.2、4.4、6.0で@Jeffのソリューションをテストしました。 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
passerbywhu

Kotlinを使用している人

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

setOnkeyListenerは、ソフトキーボードまたはハードキーボードでも機能しました。しかし、一部のデバイスのみ。私の場合、Samsung s8では動作しますが、Xiaomi mi8 seでは動作しません。

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

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
Ranjith Kumar

@Jiff ZanyEditTextに基づくWiseEditText with setSoftKeyListener(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;
    }

}
0
Qamar

この質問は古いかもしれませんが、答えは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();
}
0
BluRe.CN

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

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
rocker99

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

0
Ayaz Alifov

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

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

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

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

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
        }
    }
}
0
Hawklike