web-dev-qa-db-fra.com

Désactiver le menu contextuel EditText

Je fais un EditText vertical pour le mongol traditionnel. Je l’ai implémentée avec succès en incorporant un EditText légèrement modifié à l’intérieur d’un ViewGroup pivoté. J'ai besoin de créer un menu contextuel complètement personnalisé car le premier système ne prend pas en charge le texte vertical et ne fait pas l'objet d'une rotation lorsque ViewGroup est pivoté. Je veux donc désactiver le menu contextuel du système.

Notez que ceci est différent de ces questions qui essaient juste de désactiver le copier/coller/etc .:

Bien que le menu contextuel n'apparaisse pas dans le simulateur, il apparaît dans mon téléphone Android 5.0.2 Xiaomi. 

J'ai essayé:

Je suis ouvert aux hacks, mais j'ai besoin que cela fonctionne de manière cohérente sur tous les appareils. Mark Murphy (un type à la Chambre des communes) a écrit il y a quelque temps en réponse à un autre utilisateur essayant de faire quelque chose de similaire:

Je suppose que même si vous apportez une réponse, cela ne fonctionnera pas à travers les appareils. Les fabricants d’appareils ont eu tendance à rouler leur propre "menu contextuel" pour EditText, repoussant les tentatives des développeurs d’ajouter éléments dans ce menu contextuel. J'imagine que c'est d'essayer de bloquer cela menu contextuel aura des résultats similaires.

Suis-je à court de chance? 

La seule chose à laquelle je peux penser maintenant est de réécrire complètement TextView et EditText à partir de zéro (enfin, en modifiant le code source Android). Je connais quelqu'un d'autre qui a fait quelque chose de similaire, mais son code n'est pas open source. Avant de franchir cette étape majeure, je voudrais essayer de demander une solution plus simple ici sur Stack Overflow. 

Update: J'ai essayé de modifier le code source TextView ces deux derniers jours et cela ressemble à un projet de 6 mois. C'est une masse de classes interdépendantes. J'ai besoin d'une autre solution, mais je suis à court d'idées.

MVCE

C’est le moyen le plus simple auquel je puisse penser pour recréer le problème. Il n'y a rien de nécessaire dans ma coutume EditText. La disposition a une seule EditText faite en remplaçant le projet par défaut Hello World TextView. J'ai changé l'API min à 11 pour éviter de traiter avec des méthodes obsolètes.

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        EditText editText = (EditText) findViewById(R.id.edit_text);
        editText.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
            @Override
            public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { return false; }
            @Override
            public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { return false; }
            @Override
            public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) { return false; }
            @Override
            public void onDestroyActionMode(ActionMode actionMode) { }
        });
    }
}

Le menu contextuel du simulateur (API 24 en cours d'exécution) apparaît toujours lorsque je clique sur la poignée du curseur (mais pas sur un clic long ou un double clic). Voici une image:

 enter image description here

Sur mon téléphone Xiaomi MIUI sous Android 5.0, je reçois le menu contextuel dans toutes les situations (clic du curseur, clic long, double clic).

Mettre à jour

La solution Aritra Roy fonctionne dans le simulateur, sur d'autres appareils qu'il a testés et sur mon appareil. J'ai accepté sa réponse parce que cela résout mon problème initial. Le seul effet secondaire négatif est que la sélection de texte est également désactivée.

28
Suragch

Il y a trois choses que vous devez faire. 

ÉTAPE 1

Vous pouvez désactiver l’affichage des menus contextuels en renvoyant false à partir de ces méthodes,

mEditEext.setCustomSelectionActionModeCallback(new ActionMode.Callback() {

            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                return false;
            }

            public void onDestroyActionMode(ActionMode mode) {                  
            }

            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                return false;
            }

            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                return false;
            }
        });

ÉTAPE 2

Il est également nécessaire de désactiver le clic long dans EditText.

mEditText.setLongClickable(false);

ou, ce faisant, Android:longClickable="false" en XML.

ÉTAPE 3

Maintenant, vous devez empêcher les menus d'apparaître lorsque vous cliquez sur les poignées. La solution est simple

1) Étendre la classe EditText,

2) Remplacez isSuggestionsEnabled() et renvoyez false,

3) Créez une méthode canPaste() et renvoyez false. C'est une méthode qui se cache.

SOLUTION RAPIDE

Si vous ne voulez pas faire tout cela manuellement. Voici une classe EditText personnalisée que vous pouvez utiliser pour y parvenir rapidement. Mais je vous recommande quand même de suivre les étapes une fois pour comprendre comment les choses fonctionnent.

public class MenuHidingEditText extends EditText {
    private final Context mContext;

    public MenuHidingEditText(Context context) {
        super(context);
        this.mContext = context;

        blockContextMenu();
    }

    public MenuHidingEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;

        blockContextMenu();
    }

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

        blockContextMenu();
    }

    private void blockContextMenu() {
        this.setCustomSelectionActionModeCallback(new BlockedActionModeCallback());
        this.setLongClickable(false);
        this.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                MenuHidingEditText.this.clearFocus();
                return false;
            }
        });
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            // setInsertionDisabled when user touches the view
            this.setInsertionDisabled();
        }
        return super.onTouchEvent(event);
    }

    private void setInsertionDisabled() {
        try {
            Field editorField = TextView.class.getDeclaredField("mEditor");
            editorField.setAccessible(true);
            Object editorObject = editorField.get(this);

            Class editorClass = Class.forName("Android.widget.Editor");
            Field mInsertionControllerEnabledField = editorClass.getDeclaredField("mInsertionControllerEnabled");
            mInsertionControllerEnabledField.setAccessible(true);
            mInsertionControllerEnabledField.set(editorObject, false);
        }
        catch (Exception ignored) {
            // ignore exception here
        }
    }

    @Override
    public boolean isSuggestionsEnabled() {
        return false;
    }

    private class BlockedActionModeCallback implements ActionMode.Callback {

        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            return false;
        }

        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            return false;
        }

        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            return false;
        }

        public void onDestroyActionMode(ActionMode mode) {
        }
    }
}
18
Aritra Roy

J'ai fait ce code pour EditText, et cela a bien fonctionné pour un tel problème. 

try {
    edtName.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            edtName.setSelection(0);
        }
    });
    edtName.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {
            return true;
        }
    });
    edtName.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
        @Override
        public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { return false; }
        @Override
        public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { return false; }
        @Override
        public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) { return false; }
        @Override
        public void onDestroyActionMode(ActionMode actionMode) { }
    });
} catch (Exception e) {
    e.printStackTrace();
}
3
Rjz Satvara

la solution est très simple

public class MainActivity extends AppCompatActivity {

EditText et_0;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    et_0 = findViewById(R.id.et_0);

    et_0.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            //to keep the text selection capability available ( selection cursor)
            return true;
        }

        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            //to prevent the menu from appearing
            menu.clear();
            return false;
        }

        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            return false;
        }

        @Override
        public void onDestroyActionMode(ActionMode mode) {

        }
    });
   }
}

 enter image description here

2
Muhammad Ali
mEditText.setLongClickable(false);

C'est le moyen le plus simple de désactiver le texte modifié.

1
udayatom

C'est ainsi que vous empêchez le menu copier-coller de s'afficher de quelque manière que ce soit. Ce bogue m'a vraiment rendu fou. Comme pour tout bogue Samsung, vous savez qu'il est dans leur code, mais vous savez aussi qu'ils ne le répareront pas de sitôt. Quoi qu'il en soit, voici mur de merveille ...

  1. Vérifiez si Android.Build.Model.toLowerCase (). StartsWith ('sm-g930'). Ne correspond pas à la chaîne entière, la dernière lettre est un identificateur de version mineure. J'ai stocké ce booléen dans la variable shouldBlockCopyPaste, qui apparaîtra plus tard.

  2. Si cela correspond, vous souhaitez empêcher l'affichage du menu copier-coller. Voici comment vous le faites réellement !!!

Si vous remplacez ces 2 fonctions, vous remarquerez que mon objet shouldBlockCopyPaste est booléen, afin que les autres périphériques ne soient pas bloqués.

   @Override
   public ActionMode StartActionMode (ActionMode.Callback callback){
      if (shouldBlockCopyPaste) {
        return null;
      } else {
        return super.StartActionMode(callback);
      }
    }

   @Override
   public ActionMode StartActionMode (ActionMode.Callback callback, int type){
      if (shouldBlockCopyPaste) {
        return null;
      } else {
        return super.StartActionMode(callback, type);
      }
    }
0
self.name