web-dev-qa-db-fra.com

EditText: Désactiver le menu contextuel Coller / Remplacer lors de l'événement de clic du gestionnaire de sélection de texte

Mon objectif est d'avoir un EditText qui n'a pas de fonctionnalités de fantaisie, juste le gestionnaire de sélection de texte pour déplacer le curseur plus facilement - donc pas de menus contextuels ou de fenêtres contextuelles.

J'ai désactivé l'apparence de la barre d'action de la fonction d'édition de texte (copier/coller, etc.) en consommant l'événement de rappel ActionMode, conformément à cette solution .

La poignée de sélection centrale du texte du milieu (voir l'image ci-dessous) apparaît toujours lorsque du texte existe dans le champ et qu'un clic se produit dans le texte. Génial! Je veux garder ce comportement. Ce que je NE VEUX PAS, c'est que le menu "PASTE" apparaisse lorsque l'on clique sur la poignée de sélection de texte elle-même.

Text selection handle with paste menu

J'ai également désactivé la saisie d'un clic long pour EditText en définissant Android:longClickable="false" dans les styles XML. La désactivation du clic long empêche le menu "Coller/Remplacer" d'apparaître lorsque la souris est cliquée et maintenue (c.-à-d. Touche longue), mais lorsque la souris est cliquée (touche unique) dans le texte, la poignée de sélection de texte apparaît et lorsque le la poignée de sélection de texte elle-même est cliquée, puis l'option de menu "coller" apparaît (lorsqu'il y a du texte dans le presse-papiers). C'est ce que j'essaie d'empêcher.

D'après ce que je peux voir de la source, le ActionPopupWindow est ce qui apparaît avec les options PASTE/REPLACE. ActionPopupWindow est une variable protégée (mActionPopupWindow) dans la classe abstraite privée HandleView dans la classe publique Android.widget.Editor ...

À moins de désactiver le service de presse-papiers ou de modifier le Android code source, existe-t-il un moyen d'empêcher cela de s'afficher? J'ai essayé de définir un nouveau style pour Android:textSelectHandleWindowStyle, Et mettre Android:visibility à gone, mais cela n'a pas fonctionné (l'application s'est figée pendant un certain temps alors qu'elle aurait autrement été affichée).

18
CJBS

Solution: remplacez isSuggestionsEnabled et canPaste dans EditText.

Pour la solution rapide, copiez la classe ci-dessous - cette classe remplace la classe EditText et bloque tous les événements en conséquence.

Pour les détails granuleux, continuez à lire.

La solution consiste à empêcher le menu PASTE/REPLACE d'apparaître dans la méthode show() de la classe (non documentée) Android.widget.Editor. Avant que le menu n'apparaisse, une vérification est effectuée sur if (!canPaste && !canSuggest) return;. Les deux méthodes utilisées comme base pour définir ces variables se trouvent toutes deux dans la classe EditText:

Donc, incorporer ces mises à jour dans une classe qui a également le setCustomSelectionActionModeCallback , et le clic long désactivé , voici la classe complète pour empêcher toute modification (mais toujours afficher le - gestionnaire de sélection de texte ) pour contrôler le curseur:

package com.cjbs.widgets;

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


/**
 *  This is a thin veneer over EditText, with copy/paste/spell-check removed.
 */
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) {}
    }
} 

J'ai testé cela dans Android v4.4.2 et v4.4.3.

20
CJBS

ou utilisez simplement

yourEditText.setLongClickable(false);

OU en XML

Android:longClickable="false"

Mise à jour

En fait, l'utilisateur veut désactiver la poignée de sélection de texte elle-même

1. Créez une forme (handle.xml)

 <shape xmlns:Android="http://schemas.Android.com/apk/res/Android"
 Android:shape="rectangle" >

 <size
    Android:height="0dp"
    Android:width="0dp" />
 </shape>

2. Dans votre EditText

 Android:textSelectHandle="@drawable/handle"
14

Voici un hack pour désactiver la popup "coller". Vous devez remplacer la méthode EditText:

@Override
public int getSelectionStart() {
    for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
        if (element.getMethodName().equals("canPaste")) {
            return -1;
        }
    }
    return super.getSelectionStart();
}

Cette solution fonctionne sur les nouvelles versions de Android également, contrairement à la réponse acceptée.

7
Anton Tananaev

Je ne trouve pas un moyen de masquer le menu contextuel, mais vous pouvez désactiver le collage si l'utilisateur tape sur le menu

Créez un EditText personnalisé et remplacez la méthode onTextContextMenuItem et retournez false pour Android.R.id.paste et Android.R.id.pasteAsPlainText ID de menu.

@Override
public boolean onTextContextMenuItem(int id) {
    switch (id){
        case Android.R.id.paste:
        case Android.R.id.pasteAsPlainText:
            return false;

    }
    return super.onTextContextMenuItem(id);
}
6
Libin

Trouvé une autre solution lorsque la vue bleue (contrôleur d'insertion) n'apparaît pas du tout. J'ai utilisé la réflexion pour définir le champ booléen cible de la classe Editor. Regardez Android.widget.Editor et Android.widget.TextView pour plus de détails.

Ajoutez le code suivant dans votre EditText personnalisé (avec tout le code précédent dans cette rubrique):

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

/**
 * This method sets TextView#Editor#mInsertionControllerEnabled field to false
 * to return false from the Editor#hasInsertionController() method to PREVENT showing
 * of the insertionController from EditText
 * The Editor#hasInsertionController() method is called in  Editor#onTouchUpEvent(MotionEvent event) method.
 */

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

De plus, vous pouvez peut-être trouver le meilleur endroit que onTouch () pour appeler la méthode cible.

Testé sur Android 5.1

5

Si vous devez supprimer la suggestion COLLER, videz le presse-papiers avant le clic long.

//class 
ClipboardManager clipboard;

//oncreate 
clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("","");
clipboard.setPrimaryClip(clip);
1
Mustafa
Use this in Java file

if (Android.os.Build.VERSION.SDK_INT < 11) {
    editText.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {

        @Override`enter code here`
        public void onCreateContextMenu(ContextMenu menu, View v,
                ContextMenuInfo menuInfo) {
            // TODO Auto-generated method stub
            menu.clear();
        }
    });
} else {
    editText.setCustomSelectionActionModeCallback(new ActionMode.Callback() {

        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            // TODO Auto-generated method stub
            return false;
        }

        public void onDestroyActionMode(ActionMode mode) {
            // TODO Auto-generated method stub

        }

        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            // TODO Auto-generated method stub
            return false;
        }

        public boolean onActionItemClicked(ActionMode mode,
                MenuItem item) {
            // TODO Auto-generated method stub
            return false;
        }`enter code here`
    });
}


With this code also add Android:textSelectHandle="@drawable/handle"
<shape xmlns:Android="http://schemas.Android.com/apk/res/Android"
 Android:shape="rectangle" >

 <size
    Android:height="0dp"
    Android:width="0dp" />
 </shape>


By Using these two combinations my problem is solved.
1
user1242611

Remplacez simplement une méthode:

@Override
protected MovementMethod getDefaultMovementMethod() {
    // we don't need arrow key, return null will also disable the copy/paste/cut pop-up menu.
    return null;
}
0

J'ai trouvé un moyen simple mais fiable. L'idée est de consommer l'événement tactile, pour éviter que l'événement tactile n'atteigne le code par défaut.

  1. Pour désactiver le popup copier/coller.
  2. Pour désactiver le gestionnaire de sélection de texte.
  3. Affichage toujours du curseur à la fin du texte.
  4. Toujours montrant le clavier.

maskedEditText.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        focusAndShowKeyboard(view.getContext(), maskedEditText);
        // Consume the event.
        return true;
    }
});

private static void focusAndShowKeyboard(Context context, EditText editText) {
    editText.requestFocus();
    InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
}

enter image description here

Remarque: le curseur clignotant s'affiche toujours à la fin du texte. Juste que la capture d'écran ne peut pas la capturer.

0
Cheok Yan Cheng

Aucune des solutions ci-dessus n'a fonctionné pour moi. J'ai réussi à faire ma solution (explication après), qui a désactivé tout collage sur le EditText tout en maintenant toutes les autres opérations valides.
Principalement, vous devez remplacer cette méthode sur votre implémentation de EditText:

@Override
public boolean onTextContextMenuItem (int id) {
    if (id == Android.R.id.paste) return false;

    return super.onTextContextMenuItem(id);
}

Ainsi, en examinant le code EditText, après toutes les vérifications, le collage (et toutes les actions ContextMenu sur le EditText) se produisent à une méthode appelée onTextContextMenuItem:

public boolean onTextContextMenuItem(int id) {
    int min = 0;
    int max = mText.length();

    if (isFocused()) {
        final int selStart = getSelectionStart();
        final int selEnd = getSelectionEnd();

        min = Math.max(0, Math.min(selStart, selEnd));
        max = Math.max(0, Math.max(selStart, selEnd));
    }

    switch (id) {
        case ID_SELECT_ALL:
            // This does not enter text selection mode. Text is highlighted, so that it can be
            // bulk edited, like selectAllOnFocus does. Returns true even if text is empty.
            selectAllText();
            return true;

        case ID_PASTE:
            paste(min, max);
            return true;

        case ID_CUT:
            setPrimaryClip(ClipData.newPlainText(null, getTransformedText(min, max)));
            deleteText_internal(min, max);
            stopSelectionActionMode();
            return true;

        case ID_COPY:
            setPrimaryClip(ClipData.newPlainText(null, getTransformedText(min, max)));
            stopSelectionActionMode();
            return true;
    }
    return false;
}

Si vous remarquez, le collage ne se produira que lorsque id == ID_PASTE, donc, encore une fois, en regardant le code EditText:

static final int ID_PASTE = Android.R.id.paste;
0
Thalescm