Peristiwa kunci Android EditText delete (spasi mundur)


122

Bagaimana cara mendeteksi peristiwa kunci delete (backspace) untuk editText? Saya sudah mencoba menggunakan TextWatcher, tetapi ketika editText kosong, ketika saya menekan tombol delete, tidak ada yang terjadi. Saya ingin mendeteksi delete key press foe editText bahkan jika tidak ada teks.

Jawaban:


173

CATATAN: onKeyListenertidak berfungsi untuk keyboard lunak.

Anda dapat mengatur OnKeyListeneruntuk Anda editTextsehingga Anda dapat mendeteksi setiap tekan tombol
EDIT: Sebuah kesalahan umum kita memeriksa KeyEvent.KEYCODE_BACKuntuk backspace, tapi benar-benar itu adalah KeyEvent.KEYCODE_DEL(Benar-benar nama itu sangat membingungkan!)

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
saya baru saja mencobanya, tetapi onKeyListeners tampaknya tidak mendaftar backspaces.
stefs

3
Ini tidak akan berfungsi untuk keyboard lunak. Ini hanya akan bekerja untuk input perangkat keras.
Varundroid

6
Pada saya (saham menjalankan KitKat) Nexus4 ini tidak bekerja untuk keyboard software.
Matthias

10
JADI jika tidak berhasil untuk tombol lunak, lalu mengapa jawaban ini diterima di / di bawah platform android ..
DJphy

33
gunakan event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_DELjika Anda tidak ingin acara untuk menembak dua kali per tekan backspace
Fonix

83

Sudah lama sejak Anda bertanya tetapi saya memiliki masalah yang sama. Seperti yang telah disebutkan oleh Estel, masalah dengan pendengar utama adalah bahwa mereka hanya bekerja dengan keyboard perangkat keras. Untuk melakukan ini dengan IME (keyboard lunak) , solusinya sedikit lebih rumit.

Metode tunggal kita benar-benar ingin override adalah sendKeyEventdi EditText's InputConnectionkelas. Metode ini dipanggil saat peristiwa penting terjadi dalam IME. Tetapi untuk menimpanya, kita perlu mengimplementasikan kustom EditTextyang menggantikan onCreateInputConnectionmetode, membungkus InputConnectionobjek default dalam kelas proxy! : |

Kedengarannya rumit, tetapi inilah contoh paling sederhana yang bisa saya buat:

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

    }

}

Baris dengan panggilan ke setRandomBackgroundColoradalah tempat tindakan backspace khusus saya terjadi. Dalam hal ini, mengubah EditTextwarna latar belakang.

Jika Anda memekarkan ini dari XML ingatlah untuk menggunakan nama paket lengkap sebagai tag:

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

27
Saya baru-baru ini mengalami masalah yang sama di Jelly Bean. Saya menemukan bahwa solusi ini sebagian besar berfungsi, kecuali bahwa saya harus mengganti deleteSurroundingText (...) daripada sendKeyEvent (...) (yang tidak dipanggil sama sekali). Semoga ini bisa membantu orang lain!
Brandon

Jawaban ini, dikombinasikan dengan komentar @Brandon di atas membuat ini berfungsi untuk saya. Yang saya pikirkan sekarang adalah, bagaimana ini akan bekerja pada perangkat pra-JellyBean.
Christopher Perry

Ini berfungsi dengan jawaban yang diterima pada perangkat 2.2 dan 2.3 untuk saya.
Christoph

Sepertinya ini mengaktifkan peristiwa kunci untuk backspace dua kali pada 2.3 ...: /
Jeff

25
Ini tidak berfungsi saat teks editan kosong, ada ide tentang cara mendapatkan acara untuk tombol hapus saat teks editan kosong dan tidak memiliki teks? 4.2
Rickster

69

Ini hanyalah tambahan untuk jawaban Idris, menambahkan override ke deleteSurroundingText juga. Saya menemukan info lebih lanjut tentang itu di sini: Android: Backspace di 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
Terima kasih! The deleteSurroundingTextbit adalah persis apa yang saya butuhkan setelah mencoba banyak solusi lain.
Adam Rosenfield

5
Solusi ini telah bekerja dengan sangat baik untuk saya pada versi Android sebelumnya, tetapi sayangnya deleteSurroundingText hanya dipanggil saat menghapus spasi di 4.4 (KitKat). Saya telah menguji pada Nexus4 dan 7.
Dean

1
tampaknya deleteSurroundingText diperlukan jika EditText multiline. Aneh
Alex Sorokoletov

7
Terima kasih banyak, tidak berhasil tanpa deleteSurroundText. Android sangat acak sehingga mereka harus mengganti namanya menjadi androm.
Torsten Ojaperv

2
Ini berfungsi untuk saya, tetapi saya tidak dapat menghapus tanda baca atau spasi lagi!
jaytj95

29

Inilah solusi mudah saya, yang berfungsi untuk semua 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 ...

    } 
}

PERBARUI 17.04.18 .
Seperti yang ditunjukkan dalam komentar, solusi ini tidak melacak pers backspace jika EditText kosong (sama seperti sebagian besar solusi lainnya).
Namun, itu cukup untuk sebagian besar kasus penggunaan.
NB Jika saya harus membuat sesuatu yang serupa hari ini, saya akan melakukan:

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

Kemudian gunakan saja sebagai TextWatcher biasa:

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

Hanya yang saya butuhkan! Terima kasih!
DH28

9
TextWatcher tidak memicu pada EditText kosong
Dan Neacșu

@ Leo Droidcoder saya digunakan dalam solusi serupa. Jelas, ringkas, dan bekerja dengan sempurna ... tepuk tangan.
AJW

algoritma ini memiliki kelemahan seolah-olah Anda mengklik spasi setelah mengetik maka panjang sebelumnya lebih besar dari s.length
Marcin S.

2
Berfungsi selama Anda tidak menggunakan seleksi (pelengkapan otomatis)
Javatar

13

Saya mengirim 2 hari untuk menemukan solusi dan saya menemukan solusi yang berfungsi :) (pada tombol lunak)

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

Setelah menambahkan textwatcher ke EditText Anda:

yourEditText.addTextChangedListener(textWatcher);

Saya harap ini juga berfungsi di perangkat android lain (samsung, LG, dll).


Perangkat keinginan HTC (HTC umum meskipun :-P)
Junaid

Jika diketik satu spasi maka hitung juga == 0
Bincy Baby

Brilian no 1 jawaban bro :)
Gundu Bandgar

6
Itu sama sekali tidak berhasil. count == 0 hanya akan ada jika teks editan kosong!
Leo Droidcoder

@MarcAlexander Saya tidak yakin tentang jawaban ini, namun Anda dapat memeriksa solusi saya di jawaban di atas
Leo Droidcoder

5

Solusi sederhana saya yang bekerja dengan sempurna. Anda harus menambahkan sebuah bendera. Potongan kode saya:

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 tidak pernah memanggil emptTextview.
Janardhan R

3

Contoh pembuatan EditText dengan TextWatcher

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

TextWatcher kustom

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

untuk seseorang yang menggunakan Kotlin

addOnTextChanged tidak cukup fleksibel untuk menangani beberapa kasus (mis: mendeteksi jika pengguna menekan hapus ketika edit teks kosong)

setOnkeyListenerbekerja bahkan keyboard lunak atau hardkeyboard! tetapi hanya di beberapa perangkat . Dalam kasus saya, ini berfungsi pada Samsung s8 tetapi tidak berfungsi pada Xiaomi mi8 se.

jika Anda menggunakan kotlin, Anda dapat menggunakan fungsi crossline doOnTextChanged, itu sama addOnTextChangedtetapi callback dipicu bahkan teks edit kosong.

CATATAN: doOnTextChanged adalah bagian dari pustaka Android KTX


2
Anda mungkin menentukan bahwa doOnTextChanged fungsi ekstensi dapat diakses di pustaka Android KTX
batu

2
Tetapi tampaknya panggilan balik TIDAK "dipicu bahkan teks edit kosong". Bisakah Anda memberikan beberapa cuplikan dengan intersepsi delete (backspace) untuk kosong EditText? Thanks in advance
stone

1
ah, saya telah mengujinya ketika saya mengembangkan sebuah proyek. Dalam kasus saya pada xiaomi mi8se, ketika edittext kosong dan Anda menekan delete, tidak ada callback yang dipecat. Saya akan mencari potongan untuk kalimat ini.
Mạnh Hoàng Huynh


0

Ini sepertinya berhasil untuk saya:

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

Saya juga menghadapi masalah yang sama dalam Dialog .. karena saya menggunakan setOnKeyListener .. Tapi saya menyetel default return true. Setelah diubah seperti kode di bawah ini, itu berfungsi dengan baik untuk saya ..

    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

Berdasarkan @Jiff di ZanyEditTextsini WiseEditTextdengansetSoftKeyListener(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;
    }

}

Itu dipanggil dua kali untuk setiap peristiwa kunci hapus.
Pankaj Kumar

0

Masalah saya adalah, bahwa saya harus kustom Textwatcher, jadi saya tidak ingin menambahkan OnKeyListenerke EditTextserta saya tidak ingin membuat kustom EditText. Saya ingin mendeteksi jika backspace ditekan dalam afterTextChangedmetode saya , jadi saya tidak boleh memicu acara saya.

Beginilah cara saya menyelesaikan ini. Semoga bisa membantu seseorang.

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

Saya telah menguji solusi @ Jeff pada versi 4.2, 4.4, 6.0. Pada 4.2 dan 6.0, ini bekerja dengan baik. Tetapi pada 4.4, itu tidak berhasil.

Saya menemukan cara mudah untuk mengatasi masalah ini. Poin kuncinya adalah memasukkan karakter yang tidak terlihat ke dalam konten EditText di awal, dan jangan biarkan pengguna menggerakkan kursor sebelum karakter ini. Cara saya adalah memasukkan karakter spasi putih dengan ImageSpan Lebar Nol di atasnya. Ini kode saya.

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

Dan kita perlu menyesuaikan EditText yang memiliki SelectionChangeListener

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

}

Dan langkah terakhir

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

Dan sekarang, kita selesai ~ Kita dapat mendeteksi peristiwa kunci backspace ketika EditText tidak memiliki konten aktual, dan pengguna tidak akan tahu apa-apa tentang trik kita.


0

Pertanyaan ini mungkin sudah lama tetapi jawabannya sangat sederhana menggunakan 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();
}

Sama seperti solusi sebelumnya, ini dapat dipicu oleh pelengkapan otomatis / saran.
Stonz2

0

Saya telah menemukan solusi yang sangat sederhana yang bekerja dengan keyboard lunak.

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

Anda bisa menyetel key listener pada aktivitas tersebut, dan dalam metode callback, Anda bisa mendeteksi kunci mana yang ditekan pengguna. Kode di bawah ini untuk referensi Anda. Semoga membantu.

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

Periksa solusi ini - KEYCODE_DEL akan dilempar ke aktivitas hanya jika teks edit tidak akan menangani ini dengan sendirinya. Misalnya, ketika tidak ada teks di editText, atau ada beberapa teks, tetapi kursor ada di awal. Lucunya, dalam kasus saya, saya membutuhkan perilaku seperti itu
Anton Kizema

Dalam aktivitas saya tidak ada EditText dan saya hanya membuat keyboard muncul secara terprogram. Saya perlu menangkap setiap tombol keyboard lunak dan tampaknya ini satu-satunya solusi yang berfungsi. Yang lainnya mengganti metode dispatchKeyEvent. Sayangnya mulai dari JellyBean, IME tidak mengirimkan KeyEvent untuk tombol DELETE. developer.android.com/reference/android/view/KeyEvent.html
Bemipefe
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.