EditTextの削除(バックスペース)キーイベントを検出するにはどうすればよいですか? TextWatcherを使用してみましたが、editTextが空の場合、deleteキーを押しても何も起こりません。テキストがない場合でも、editTextの削除キーが押されたことを検出したい。
注: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;
}
});
あなたが尋ねてからしばらく経ちましたが、私は同じ問題を抱えていました。 Estelで既に述べたように、キーリスナーの問題は、ハードウェアキーボードでのみ機能することです。 IME(ソフトキーボード)でこれを行うには、解決策がもう少し複雑です。
実際にオーバーライドしたいメソッドは、sendKeyEvent
のEditText
クラスの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>
これは、イドリスの答えへの単なる追加であり、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);
}
}
}
すべての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
}
});
私は解決策を見つけるために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など)でも機能することを願っています。
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) {
}
}
完璧に機能する私のシンプルなソリューション。フラグを追加する必要があります。私のコードスニペット:
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
}
}
バージョン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に実際のコンテンツがなく、ユーザーがトリックについて何も知らない場合、バックスペースキーイベントを検出できます。
Kotlinを使用している人
addOnTextChanged
柔軟性に欠けるいくつかのケースを処理する(例:編集テキストが空のときにユーザーが削除を押したかどうかを検出する)
setOnkeyListener
は、ソフトキーボードまたはハードキーボードでも機能しました。しかし、一部のデバイスのみ。私の場合、Samsung s8では動作しますが、Xiaomi mi8 seでは動作しません。
kotlinを使用している場合、クロスライン関数doOnTextChanged
を使用できます。これはaddOnTextChanged
と同じですが、編集テキストが空でもコールバックがトリガーされます。
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
}
});
@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;
}
}
この質問は古いかもしれませんが、答えは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();
}
これは私のために働いているようです:
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();
}
}
Stackoverflowにも同様の質問があります。 EditText
メソッドを含むInputConnection
オブジェクトにアクセスするには、deleteSurroundingText
をオーバーライドする必要があります。削除(バックスペース)イベントを検出するのに役立ちます。私がそこに提供した解決策を見てください Android-バックスペースをキャプチャできません/ソフトでキーボードを押して削除してください
私の問題は、カスタムTextwatcher
があったため、OnKeyListener
をEditText
に追加したくなかっただけでなく、カスタム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
}
}
ソフトキーボードで動作する本当に簡単なソリューションを見つけました。
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
}
}
}