web-dev-qa-db-fra.com

Android intercepter coller \ copier \ couper sur editText

Comment puis-je intercepter ce genre d'événements?

J'ai besoin d'ajouter de la logique lorsque l'utilisateur essaie de coller du texte dans mon EditText je sais que je peux utiliser TextWatcher mais ce point d'entrée n'est pas bon pour moi car je n'ai besoin que d'intercepter en cas de collage et pas à chaque fois que l'utilisateur appuie sur mon EditText,

34
and_dev

Il semble que vous ne puissiez pas faire grand-chose en utilisant l'API: événement de collage Android

Lecture de la source à la rescousse!

J'ai creusé dans le Android Source du TextView (EditText est un TextView avec une configuration différente) et j'ai découvert que le menu utilisé offrir les options couper/copier/coller est juste une modification ContextMenu ( source ).

Comme pour un menu contextuel normal, la vue doit créer le menu ( source ) puis gérer l'interaction dans une méthode de rappel ( source ).

Parce que la méthode de gestion est public, nous pouvons simplement y accrocher en étendant EditText et en écrasant la méthode pour réagir sur les différentes actions. Voici un exemple d'implémentation:

import Android.content.Context;
import Android.util.AttributeSet;
import Android.widget.EditText;
import Android.widget.Toast;

/**
 * An EditText, which notifies when something was cut/copied/pasted inside it.
 * @author Lukas Knuth
 * @version 1.0
 */
public class MonitoringEditText extends EditText {

    private final Context context;

    /*
        Just the constructors to create a new EditText...
     */
    public MonitoringEditText(Context context) {
        super(context);
        this.context = context;
    }

    public MonitoringEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
    }

    public MonitoringEditText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.context = context;
    }

    /**
     * <p>This is where the "magic" happens.</p>
     * <p>The menu used to cut/copy/paste is a normal ContextMenu, which allows us to
     *  overwrite the consuming method and react on the different events.</p>
     * @see <a href="http://grepcode.com/file/repository.grepcode.com/Java/ext/com.google.Android/android/2.3_r1/Android/widget/TextView.Java#TextView.onTextContextMenuItem%28int%29">Original Implementation</a>
     */
    @Override
    public boolean onTextContextMenuItem(int id) {
        // Do your thing:
        boolean consumed = super.onTextContextMenuItem(id);
        // React:
        switch (id){
            case Android.R.id.cut:
                onTextCut();
                break;
            case Android.R.id.paste:
                onTextPaste();
                break;
            case Android.R.id.copy:
                onTextCopy();
        }
        return consumed;
    }

    /**
     * Text was cut from this EditText.
     */
    public void onTextCut(){
        Toast.makeText(context, "Cut!", Toast.LENGTH_SHORT).show();
    }

    /**
     * Text was copied from this EditText.
     */
    public void onTextCopy(){
        Toast.makeText(context, "Copy!", Toast.LENGTH_SHORT).show();
    }

    /**
     * Text was pasted into the EditText.
     */
    public void onTextPaste(){
        Toast.makeText(context, "Paste!", Toast.LENGTH_SHORT).show();
    }
}

Maintenant, lorsque l'utilisateur utilise couper/copier/coller, un Toast est affiché (bien sûr, vous pouvez aussi faire d'autres choses).

La chose intéressante est que cela fonctionne jusqu'à Android 1.5 et vous n'avez pas besoin de recréer le contexte -menu (comme suggéré dans la question liée ci-dessus), qui gardera l'apparence constante de la plate-forme (par exemple avec HTC Sense).

77
Lukas Knuth

Il existe une manière beaucoup plus simple, bien que non fiable à 100%.

Ajoutez TextChangedListener à votre zone de saisie:

EditText et = (EditText) mView.findViewById(R.id.yourEditText);
et.addTextChangedListener(new TextWatcher() {

  @Override
  public void onTextChanged(CharSequence s, int start, int before, int count) {
     if (count > 2) toast("text was pasted");
  }

  @Override
  public void beforeTextChanged(CharSequence s, int start, int count, int after) {

  }

  public void afterTextChanged(Editable s) {

  }
});

Si le texte change pour plus de 2 caractères, vous pouvez supposer qu'il a été collé (certains smileys prennent deux caractères).

Bien sûr, il ne détectera pas le collage lorsque l'utilisateur colle 1 ou deux caractères, et il signalera à tort le collage si le changement de texte a été déclenché par autre chose.

Mais pour dans la plupart des cas, cela fait le travail ????

2
lenooh