EditText: désactiver la fonction Coller / remplacer le menu pop-up sur le Gestionnaire de sélection de texte.

mon but est d'avoir un EditText qui n'a pas de fonctionnalités fantaisistes, juste le Gestionnaire de sélection de texte pour déplacer le curseur plus facilement -- donc pas de menus contextuels ou pop-ups.

j'ai désactivé l'apparence de la fonction d'édition de texte actionbar (copier / coller etc.) en consommant L'événement de rappel ActionMode, comme dans cette solution .

la poignée de sélection du texte du milieu (voir l'image ci-dessous) apparaît toujours lorsque le texte existe dans le champ et un clic se produit dans le texte. Grand! Je veux garder ce comportement. Ce que je ne veux pas, c'est que le menu "coller" apparaisse lorsque le texte Select Handle lui-même est cliqué.

Text selection handle with paste menu

j'ai aussi désactivé l'entrée de clic long pour L'EditText en mettant android:longClickable="false" dans les styles XML. Désactiver le long clic empêche le menu "coller / remplacer" d'apparaître lorsque la souris est cliquée et maintenue (c.-à-d. Long touch), cependant, lorsque la souris est cliquée (simple touche) dans le texte, la poignée de sélection de texte apparaît, et lorsque la poignée de sélection de texte elle-même est cliquée, alors l'option de menu "coller" apparaît (quand il y a du texte dans le presse-papier). C'est ce que j'essaie d'éviter.

D'après ce que je peux voir de la source, le ActionPopupWindow est ce qui apparaît avec les options pâte/REPLACE. ActionPopupWindow est une variable protégée (mActionPopupWindow) dans la classe des abstracts privés. HandleView au sein de la classe publique android.widget.Éditeur...

à moins de désactiver le service de presse-papiers ou d'éditer le code source Android, est-ce qu'il y a un moyen que je puisse empêcher que cela se montre? J'ai essayé de définir un nouveau style pour android:textSelectHandleWindowStyle , et mettre android:visibility à gone , mais il n'a pas fonctionné (app figé pendant un certain temps quand il aurait autrement montré).

16
demandé sur CJBS 2015-01-10 01:03:49

11 réponses

Solution: remplacer isSuggestionsEnabled et canPaste dans EditText .

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

pour les détails, continuez à lire.

la solution consiste à éviter que le menu "coller/remplacer" apparaisse dans le menu show() méthode 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 qui sont utilisées comme base pour définir ces variables sont à la fois dans la classe EditText :

donc en incorporant ces mises à jour dans une classe qui a également le setCustomSelectionActionModeCallback , et le désactivé long-click , voici la classe complète pour empêcher toute édition (mais toujours afficher le manuel de sélection de texte ) pour le contrôle du 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é ceci sur Android v4.4.2 et v4.4.3.

18
répondu CJBS 2017-05-23 11:47:23

ou tout simplement utiliser

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éer une forme (la poignée.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 texte

 android:textSelectHandle="@drawable/handle"
14
répondu Murtaza Khursheed Hussain 2015-01-20 04:59:33

a trouvé une autre solution lorsque le Blue view (contrôleur d'insertion) n'est pas apparu du tout. J'ai utilisé la réflexion pour définir le champ cible booléen de la classe Editor. Regardez les android.widget.Editeur et Androïde.widget.TextView pour plus de détails.

ajoutez le code suivant dans votre texte personnalisé (avec tout le code précédent dans ce sujet):

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

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

testé sur Android 5.1

5
répondu Vladimir Ryhlitskiy 2015-05-27 18:24:37

Je ne trouve pas le moyen de cacher le popup du menu, mais vous pouvez désactiver du collage si l'utilisateur tape sur le menu

créer un personnalisé EditText et outrepasser la méthode onTextContextMenuItem et retourner 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);
}
5
répondu Libin 2016-06-17 17:42:51

voici un hack pour désactiver "paste" popup. Vous devez remplacer EditText méthode:

@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 D'Android ainsi, contrairement à la réponse acceptée.

4
répondu Anton Tananaev 2017-01-19 22:14:57
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
répondu user1242611 2015-08-28 10:29:35

si vous avez besoin supprimer la suggestion de pâte, effacer le presse-papiers avant le long clic.

//class 
ClipboardManager clipboard;

//oncreate 
clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("","");
clipboard.setPrimaryClip(clip);
1
répondu Mustafa 2017-01-31 20:47:34

aucune des solutions ci-dessus n'a fonctionné pour moi. J'ai réussi à faire ma solution (explication après), qui a désactivé coller n'importe quoi sur L'EditText tout en maintenant toutes les autres opérations valides.

Principalement, Vous devez outrepasser cette méthode sur votre mise en œuvre D'EditText:

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

    return super.onTextContextMenuItem(id);
}

donc la recherche du code EditText, après tous les contrôles, coller (et toutes les actions ContextMenu sur L'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
répondu Thalescm 2016-07-19 20:36:40

j'ai trouvé un moyen simple mais fiable. L'idée est que l'événement Consumer away the touch, pour empêcher l'événement touch de souligner le code par défaut reach.

  1. Pour désactiver le copier/coller de popup.
  2. pour désactiver le gestionnaire de sélection de texte.
  3. montrant toujours le curseur à la fin du texte.
  4. montrant toujours 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

Note, le curseur clignotant apparaît toujours à la fin du texte. Juste que la capture d'écran impossible à capturer.

0
répondu Cheok Yan Cheng 2017-06-09 07:53:24

juste outrepasser 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
répondu Oleksandr Kucherenko 2018-03-07 15:18:31

vous pouvez utiliser ce code:

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

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

Returning false from onCreateActionMode va désactiver les options Couper,copier,coller dans le niveau D'API supérieur à 11.

-1
répondu Hardik Chauhan 2015-01-15 14:20:56