Evento chiave Android EditText elimina (backspace)


122

Come posso rilevare un evento chiave di cancellazione (backspace) per un editText? Ho provato a usare TextWatcher, ma quando editText è vuoto, quando premo il tasto Canc, non succede nulla. Voglio rilevare la pressione del tasto Elimina per un editText anche se non ha testo.

Risposte:


173

NOTA: onKeyListenernon funziona per le tastiere soft.

È possibile impostare OnKeyListenerper voi editTextin modo da poter rilevare qualsiasi premere il tasto
EDIT: Un errore comune stiamo controllando KeyEvent.KEYCODE_BACKper backspace, ma in realtà è KeyEvent.KEYCODE_DEL(davvero quel nome è molto confusa!)

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
L'ho appena provato, ma a quanto pare gli onKeyListeners non registrano i backspace.
stefs

3
Non funzionerà con la tastiera morbida. Funzionerà solo per l'input hardware.
Varundroid

6
Sul mio (magazzino con KitKat) Nexus4 questo non lavoro per la tastiera software.
Matthias

10
Quindi, se non funziona per i tasti
virtuali

33
utilizzare event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_DELse non si desidera che l'evento si attivi due volte per ogni pressione di backspace
Fonix

83

È passato un po 'di tempo dall'ultima volta che me l'hai chiesto, ma ho avuto lo stesso problema. Come già accennato da Estel, il problema con gli ascoltatori chiave è che funzionano solo con tastiere hardware. Per farlo con un IME (tastiera morbida) , la soluzione è un po 'più elaborata.

L'unico metodo che in realtà desidera ignorare è sendKeyEventla EditText's InputConnectiondi classe. Questo metodo viene chiamato quando si verificano eventi chiave in un IME. Ma per sovrascrivere questo, dobbiamo implementare un custom EditTextche sovrascrive il onCreateInputConnectionmetodo, avvolgendo l' InputConnectionoggetto predefinito in una classe proxy! : |

Sembra complicato, ma ecco l'esempio più semplice che potrei escogitare:

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

    }

}

La linea con la chiamata a setRandomBackgroundColorè dove si verifica la mia azione speciale di backspace. In questo caso, cambiando il EditTextcolore di sfondo di.

Se lo stai gonfiando da XML, ricorda di utilizzare il nome completo del pacchetto come tag:

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

27
Recentemente ho riscontrato lo stesso problema su Jelly Bean. Ho scoperto che questa soluzione per lo più funzionava, tranne per il fatto che dovevo sovrascrivere deleteSurroundingText (...) invece di sendKeyEvent (...) (che non veniva chiamato affatto). Spero che questo aiuti qualcun altro!
Brandon

Questa risposta, combinata con il commento di @Brandon sopra, ha funzionato per me. Quello che mi chiedo ora è come funzionerà sui dispositivi pre-JellyBean.
Christopher Perry

Per me funziona con la risposta accettata sui dispositivi 2.2 e 2.3.
Christoph

sembra che stia attivando l'evento chiave per backspace due volte il 2.3 ...: /
Jeff

25
Questo non funziona quando il testo editore è vuoto, qualche idea su come ottenere un evento per il tasto Canc quando il testo editore è vuoto e non ha testo? 4.2
Rickster

69

Questa è solo un'aggiunta alla risposta di Idris, aggiungendo anche l'override a deleteSurroundingText. Ho trovato maggiori informazioni su questo qui: Android: Backspace in 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
Grazie! Il deleteSurroundingTextbit era esattamente ciò di cui avevo bisogno dopo aver provato innumerevoli altre soluzioni.
Adam Rosenfield

5
Questa soluzione ha funzionato molto bene per me sulle versioni precedenti di Android, ma sfortunatamente deleteSurroundingText viene chiamato solo quando si rimuovono gli spazi bianchi su 4.4 (KitKat). Ho provato sia Nexus4 che 7.
Dean

1
sembra che deleteSurroundingText sia richiesto quando EditText è multilinea. Strano
Alex Sorokoletov

7
Grazie mille, non ha funzionato senza deleteSurroundText. Android è così casuale che dovrebbero rinominarlo in androm.
Torsten Ojaperv

2
Per me funziona, ma non posso più eliminare la punteggiatura o gli spazi!
jaytj95

29

Ecco la mia semplice soluzione, che funziona per tutte le 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 ...

    } 
}

AGGIORNAMENTO 17.04.18 .
Come sottolineato nei commenti, questa soluzione non tiene traccia della pressione di backspace se EditText è vuoto (lo stesso della maggior parte delle altre soluzioni).
Tuttavia, è sufficiente per la maggior parte dei casi d'uso.
PS Se dovessi creare qualcosa di simile oggi, farei:

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

Quindi usalo come un normale 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 
        }
    });

Proprio quello che mi serve! Grazie!
DH28

9
Il TextWatcher non si attiva su un EditText vuoto
Dan Neacșu

@ Leo Droidcoder che ho usato in una soluzione simile. Chiaro, conciso e funziona perfettamente ... applausi.
AJW

questo algoritmo ha un difetto come se si fa clic su uno spazio dopo aver digitato la lunghezza precedente è maggiore della lunghezza
Marcin S.

2
Funziona finché non usi la selezione (completamento automatico)
Javatar

13

Ho inviato 2 giorni per trovare una soluzione e ne ho trovata una funzionante :) (sui tasti funzione)

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

Dopo aver aggiunto il textwatcher al tuo EditText:

yourEditText.addTextChangedListener(textWatcher);

Spero che funzioni anche su altri dispositivi Android (Samsung, LG, ecc.).


Dispositivo HTC desiderio (HTC è comune però :-P)
Junaid

se digitato uno è uno spazio bianco, allora conta anche == 0
Bincy Baby

Brillante risposta no 1 fratello :)
Gundu Bandgar

6
Non funziona completamente. count == 0 sarà solo quando edittext è vuoto!
Leo Droidcoder

@MarcAlexander Non sono sicuro di questa risposta, tuttavia puoi controllare la mia soluzione nella risposta sopra
Leo Droidcoder

5

La mia semplice soluzione che funziona perfettamente. Dovresti aggiungere una bandiera. Il mio snippet di codice:

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 non ha mai chiamato emptTextview.
Janardhan R

3

Esempio di creazione di EditText con 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 personalizzato

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

per qualcuno che sta usando Kotlin

addOnTextChanged non è abbastanza flessibile per gestire alcuni casi (es: rileva se l'utente preme cancella quando il testo di modifica era vuoto)

setOnkeyListenerha funzionato anche tastiera morbida o tastiera dura! ma solo su alcuni dispositivi . Nel mio caso, funziona su Samsung s8 ma non su Xiaomi mi8 se.

se stai usando kotlin, puoi usare la funzione crossline doOnTextChanged , è la stessa diaddOnTextChanged ma viene attivato il callback anche se il testo di modifica era vuoto.

NOTA: doOnTextChanged fa parte della libreria KTX di Android


2
Probabilmente potresti specificare che la doOnTextChanged funzione di estensione è accessibile nella libreria KTX di Android
stone

2
Ma sembra che la richiamata NON sia "attivata anche la modifica del testo era vuota". Potresti fornire uno snippet con l'intercettazione di cancellazione (backspace) per vuoto EditText? Grazie in anticipo
pietra

1
ah, devo testarlo quando sviluppo un progetto. Nel mio caso è su xiaomi mi8se, quando edittext è vuoto e premi cancella, nessuna richiamata viene attivata. Cercherò lo snippet per questa frase.
Mạnh Hoàng Huynh


0

Questo sembra funzionare per me:

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

Ho anche riscontrato lo stesso problema in Dialog .. perché sto usando setOnKeyListener .. Ma ho impostato il ritorno di default true. Dopo la modifica come sotto il codice funziona bene per me ..

    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

Basato su @Jiff, ZanyEditTextecco WiseEditTextconsetSoftKeyListener(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;
    }

}

Viene chiamato due volte per ogni evento chiave di eliminazione.
Pankaj Kumar

0

Il mio problema era che avevo personalizzato Textwatcher, quindi non volevo aggiungere OnKeyListenera un EditTextcosì come non volevo creare personalizzato EditText. Volevo rilevare se backspace è stato premuto nel mio afterTextChangedmetodo, quindi non avrei dovuto attivare il mio evento.

Ecco come l'ho risolto. Spero possa essere utile per qualcuno.

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

Ho testato la soluzione di @ Jeff sulla versione 4.2, 4.4, 6.0. Su 4.2 e 6.0 funziona bene. Ma su 4.4, non funziona.

Ho trovato un modo semplice per aggirare questo problema. Il punto chiave è inserire un carattere invisibile nel contenuto di EditText all'inizio e non lasciare che l'utente muova il cursore prima di questo carattere. Il mio modo è inserire uno spazio vuoto con un ImageSpan di larghezza zero su di esso. Ecco il mio codice.

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

E abbiamo bisogno di un EditText personalizzato che abbia un 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);
}

}

E l'ultimo passaggio

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

E ora, abbiamo finito ~ Possiamo rilevare l'evento chiave backspace quando EditText non ha contenuti effettivi e l'utente non saprà nulla del nostro trucco.


0

Questa domanda potrebbe essere vecchia ma la risposta è davvero semplice utilizzando un 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();
}

Proprio come le soluzioni precedenti, questo può essere attivato dal completamento automatico / suggerimenti.
Stonz2

0

Ho trovato una soluzione davvero semplice che funziona con una tastiera morbida.

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

È possibile impostare un listener di chiavi sull'attività e, nel metodo di richiamata, è possibile rilevare il tasto premuto dall'utente. Il codice seguente è per tuo riferimento. Spero che sia d'aiuto.

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

Controllata questa soluzione: KEYCODE_DEL verrà lanciato in attività solo se il testo di modifica non lo gestirà da solo. Ad esempio, quando non c'è testo in editText, o c'è del testo, ma il cursore è all'inizio. È divertente che nel mio caso ho bisogno esattamente di quel comportamento
Anton Kizema

Nella mia attività non c'è EditText e faccio solo apparire la tastiera in modo programmatico. Devo catturare ogni tasto della tastiera virtuale e questa sembra l'unica soluzione funzionante. L'altro sta sovrascrivendo il metodo dispatchKeyEvent. Sfortunatamente a partire da JellyBean l'IME non invia un KeyEvent per la chiave DELETE. developer.android.com/reference/android/view/KeyEvent.html
Bemipefe
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.