Désactiver le menu contextuel EditText

Je fais une verticale EditText pour le mongol traditionnel. Je l'ai implémenté avec succès en intégrant 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 système ne supporte pas le texte vertical et n'est pas non plus pivoté lorsque le ViewGroup est pivoté. Donc, je veux désactiver complètement le menu contextuel du système.

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

Bien que je ne reçois pas le menu contextuel apparaissant dans le simulateur, je l'obtiens apparaissant dans mon Android 5.0.2 Xiaomi téléphone.

J'ai essayé:

Je suis ouvert aux hacks mais j'en ai besoin pour fonctionner de manière cohérente sur tous les appareils. Mark Murphy (un gars de Commons) a écrit quelque temps en réponse à un autre utilisateur essayant de faire quelque chose de similaire:

Je soupçonne que même si vous venez avec une réponse, il ne fonctionnera pas à travers les dispositifs. Appareil les fabricants ont eu tendance à rouler leurs propre "menu contextuel" pour EditText, battant les tentatives des développeurs d'ajouter éléments dans ce menu contextuel. Je suppose que d'essayer de bloquer cela menu contextuel aura des résultats similaires.

Je Suis hors de la 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 la 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 prendre cette étape majeure, je veux essayer de demander une solution plus simple ici sur Stack Overflow.

Update: j'essaie de modifier le code source TextView depuis deux 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 la façon la plus simple de recréer le problème. Il n'y a rien de nécessaire de ma coutume EditText. A la mise en page un seul EditText fait en remplaçant le projet par défaut de 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 (exécutant API 24) s'affiche toujours lorsque je clique sur la poignée du curseur (mais pas sur un clic long ou un double clic). Voici une image:

entrez la description de l'image ici

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

Mise à jour

La solution D'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 car elle résout mon problème initial. Le seul effet secondaire est que la sélection de texte est également désactivée.

26
demandé sur Community 2017-01-16 12:33:22

6 réponses

, 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 faire ceci, {[3] } 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) Remplacer isSuggestionsEnabled() et retour false,

3) créez une méthode canPaste() et renvoyez false. C'est une méthode de masquage.

SOLUTION RAPIDE

Si vous ne voulez pas faire tout manuellement. Voici une classe EditText personnalisée que vous pouvez utiliser pour cela rapidement. Mais je vous recommande toujours de passer par 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) {
        }
    }
}
13
répondu Aritra Roy 2017-01-23 15:22:54

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
répondu Rjz Satvara 2017-01-23 07:46:53
mEditText.setLongClickable(false);

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

1
répondu udayatom 2017-01-23 04:24:49

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

        }
    });
   }
}

entrez la description de l'image ici

1
répondu Muhammad Ali 2018-07-07 10:40:55

C'est ainsi que vous empêchez le menu copier coller d'apparaître de quelque manière que ce soit. Ce bug m'a vraiment rendu fou, et comme avec tout bug Samsung, vous le savez dans leur code, mais vous savez aussi qu'ils ne le répareront pas de sitôt. Quoi qu'il en soit, voici Wonder wall...

  1. Vérifiez si Android.Construire.Modèle.toLowerCase().commence avec ('sm-g930'). Ne correspond pas à la chaîne entière, la dernière lettre est un identifiant de version mineur. J'ai stocké ce booléen dans la variable shouldBlockCopyPaste qui apparaît tard.

  2. Si elle correspond, vous voulez bloquer le menu copier coller de l'affichage. C'est la façon dont vous avez RÉELLEMENT le FAIRE!!!

Remplacer ces 2 fonctions, vous remarquerez mon booléen shouldBlockCopyPaste, c'est donc d'autres appareils ne sont 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
répondu self.name 2017-06-02 18:07:28

Essayez ceci

mEditText.setClickable(false);
mEditText.setEnabled(false);

Mise à jour

Essayez cette solution en étendant Edittext,

import android.content.Context;
import android.util.AttributeSet;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.EditText;

public class NoMenuEditText extends EditText
{
private final Context context;

/** This is a replacement method for the base TextView class' method of the same name. This 
 * method is used in hidden class android.widget.Editor to determine whether the PASTE/REPLACE popup
 * appears when triggered from the text insertion handle. Returning false forces this window
 * to never appear.
 * @return false
 */
boolean canPaste()
{
   return false;
}

/** This is a replacement method for the base TextView class' method of the same name. This method
 * is used in hidden class android.widget.Editor to determine whether the PASTE/REPLACE popup
 * appears when triggered from the text insertion handle. Returning false forces this window
 * to never appear.
 * @return false
 */
@Override
public boolean isSuggestionsEnabled()
{
    return false;
}

public NoMenuEditText(Context context)
{
    super(context);
    this.context = context;
    init();
}

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

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

private void init()
{
    this.setCustomSelectionActionModeCallback(new ActionModeCallbackInterceptor());
    this.setLongClickable(false);
}


/**
 * Prevents the action bar (top horizontal bar with cut, copy, paste, etc.) from appearing
 * by intercepting the callback that would cause it to be created, and returning false.
 */
private class ActionModeCallbackInterceptor implements ActionMode.Callback
{
    private final String TAG = NoMenuEditText.class.getSimpleName();

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

Référence: https://stackoverflow.com/a/28893714/5870896

-1
répondu Secret Coder 2017-05-23 11:47:35