Come disabilitare copia / incolla da / a EditText


131

Nella mia applicazione, c'è una schermata di registrazione, in cui non voglio che l'utente sia in grado di copiare / incollare il testo nel EditTextcampo. Ho impostato uno onLongClickListenersu ciascuno in EditTextmodo che il menu di scelta rapida che mostra il metodo copia / incolla / input e altre opzioni non venga visualizzato. Quindi l'utente non sarà in grado di copiare / incollare nei campi Modifica.

 OnLongClickListener mOnLongClickListener = new OnLongClickListener() {

        @Override
        public boolean onLongClick(View v) {
            // prevent context menu from being popped up, so that user
            // cannot copy/paste from/into any EditText fields.
            return true;
        }
    };

Ma il problema sorge se l'utente ha abilitato una tastiera di terze parti diversa da quella predefinita di Android, che può avere un pulsante per copiare / incollare o che può mostrare lo stesso menu contestuale. Quindi, come posso disabilitare copia / incolla in quello scenario?

Per favore fatemi sapere se ci sono altri modi per copiare / incollare. (e possibilmente come disabilitarli)

Qualsiasi aiuto sarebbe apprezzato.


Se l'operazione "incolla" proviene da un IME, allora non hai un modo standard per distinguerlo dai normali tasti. Un'idea da provare è misurare il tempo tra l'arrivo di ogni personaggio e se il tempo è troppo breve, i personaggi provengono da un'operazione "incolla".
BitBank,

sembra essere una sporca solitudine! vale la pena dare un'occhiata però.
rDroid

1
usa android: longClickable = "false"
Azay Gupta,

Risposte:


112

Se si utilizza API livello 11 o superiore, è possibile interrompere la visualizzazione dei menu di scelta rapida copia, incolla, taglia e personalizzati.

edittext.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;
            }
        });

La restituzione di false da onCreateActionMode (ActionMode, Menu) impedirà l'avvio della modalità di azione (selezionare tutte le azioni, Taglia, Copia e Incolla).


1
che dire del livello API inferiore a 13?
Jonathan,

1
Non capisco nessuno dei commenti, questo esempio funziona api11 +, pre-api11 non c'era copia e incolla IIRC
scottyab

28
Non funziona per me.Il pulsante Incolla apparirà in caso di toccare l'indicatore del cursore blu.
Annullare il

8
Inoltre non funziona per me. Toccando due volte viene visualizzato il menu di copia-incolla.
Android Killer

questo non funziona più su Android 6.0, controllare questa risposta stackoverflow.com/questions/27869983/...
has19

132

Il metodo migliore è utilizzare:

etUsername.setLongClickable(false);

58
Oppure, solo in xml android:longClickable="false":)
lomza,

19
Il pulsante Incolla verrà visualizzato in caso di tocco sull'indicatore del cursore blu.
Annullare il

16
Ciò eviterà sicuramente che la vista sia cliccabile a lungo, ma i controlli di modifica possono anche essere richiesti toccando due volte il testo, il che significa che questa soluzione non è completa. Tienilo a mente per i tuoi scopi.
Kevin Grant,

1
Inoltre, le scorciatoie da tastiera potrebbero ancora funzionare (Ctrl + C) con tastiere esterne.
Oleg Vaskevich,

Questo non funziona su Ice Cream Sandwich perché le opzioni degli Appunti possono essere aperte toccando due volte il testo e toccando a lungo.
Paul Wintz,

44

Puoi farlo disabilitando la pressione prolungata di EditText

Per implementarlo, basta aggiungere la seguente riga nell'xml -

android:longClickable="false"

6
il problema era che il mio utente dell'app aveva una tastiera di terze parti con un pulsante copia e incolla.
rDroid

3
un altro problema è che puoi selezionare il testo con un doppio tocco e mostra di nuovo copia / incolla
Nikola

37

Sono in grado di disabilitare la funzionalità copia e incolla con quanto segue:

textField.setCustomSelectionActionModeCallback(new ActionMode.Callback() {

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

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

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

    public void onDestroyActionMode(ActionMode actionMode) {
    }
});

textField.setLongClickable(false);
textField.setTextIsSelectable(false);

Spero che funzioni per te ;-)


Questa è la stessa identica soluzione con cui sono arrivato in base alle altre risposte sopra. Questo dovrebbe essere contrassegnato come la soluzione corretta poiché gestisce i casi limite che gli altri non fanno
Andrew Hoefling

2
Questa opzione blocca la copia ma è comunque possibile incollarla facendo clic sul cursore.
Mehul Kanzariya,

12

qui è un modo migliore per disabilitare il taglio copia incolla di editText funziona in tutte le versioni

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

Questo ha funzionato per me, dovevo solo aggiungere @TargetApi (Build.VERSION_CODES.HONEYCOMB)
Sheepdogsheep

11

Oltre a setCustomSelectionActionModeCallback e alle soluzioni a clic lungo disabilitate , è necessario impedire la visualizzazione dei menu PASTE / REPLACE quando si fa clic sulla maniglia di selezione del testo, come nell'immagine seguente:

Maniglia di selezione testo con menu Incolla

La soluzione sta nel prevenire la visualizzazione del menu PASTE / REPLACE nel show()metodo della android.widget.Editorclasse (non documentata) . Prima che venga visualizzato il menu, viene eseguito un controlloif (!canPaste && !canSuggest) return; . I due metodi utilizzati come base per impostare queste variabili sono entrambi nella EditTextclasse:

Una risposta più completa è disponibile qui .


Questa è la soluzione CORRETTA e COMPLETA
FireZenk,

In alcuni dispositivi invece l'opzione Incolla Appunti è visibile, funge solo da incolla. ho controllato i collegamenti ma sono in grado di impedire l'incollaggio ma non gli appunti. qualche idea ?
Richa,

11

Soluzione di Kotlin:

fun TextView.disableCopyPaste() {
    isLongClickable = false
    setTextIsSelectable(false)
    customSelectionActionModeCallback = object : ActionMode.Callback {
        override fun onCreateActionMode(mode: ActionMode?, menu: Menu): Boolean {
            return false
        }

        override fun onPrepareActionMode(mode: ActionMode?, menu: Menu): Boolean {
            return false
        }

        override fun onActionItemClicked(mode: ActionMode?, item: MenuItem): Boolean {
            return false
        }

        override fun onDestroyActionMode(mode: ActionMode?) {}
    }
}

Quindi puoi semplicemente chiamare questo metodo sul tuo TextView:

override fun onCreate() {
    priceEditText.disableCopyPaste()
}

1
Ciao, sto usando questo approccio, ma ricevo un Type mismatcherrore con questa descrizione Required:ActionMode.Callback! Found: in questa parte object: ActionMode.Callback. Qualche idea sul perché potrebbe non funzionare?
Abdul Mateen,

8

Utilizzando altre soluzioni, API 26 (Oreo) mostrava ancora la maniglia del cursore con un singolo tocco sul testo inserito, quindi è possibile visualizzare il menu. Solo una combinazione di soluzioni può risolvere il mio problema.

public class CustomEditText extends EditText {

    public CustomEditText(Context context) {
        super(context);
        init();
    }

    public CustomEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CustomEditText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

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

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            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
        }
    }

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

5

Se non si desidera disabilitare il clic lungo perché è necessario eseguire alcune funzionalità con un clic lungo, invece di restituire true è un'opzione migliore per farlo.

Il tuo clic lungo edittext sarà così.

edittext.setOnLongClickListener(new View.OnLongClickListener() {
      @Override
      public boolean onLongClick(View v) {
            //  Do Something or Don't
            return true;
      }
});

Come da documentazione, la restituzione di "Vero" indica che è stato gestito un clic lungo, quindi non è necessario eseguire operazioni predefinite.

Ho provato questo a livello API 16, 22 e 25. Funziona bene per me. Spero che questo possa aiutare.


1
Buona In alternativa, basta impostare android:longClickable="false"in XML
Alex Semeniuk,


3

Ecco un trucco per disabilitare il popup "incolla". Devi sostituire il EditTextmetodo:

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

Simile può essere fatto per le altre azioni.


puoi dirlo per disabilitare gli Appunti
Richa il

3

Ho testato questa soluzione e funziona

    mSubdomainEditText.setLongClickable(false);
    mSubdomainEditText.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;
      }
    });

1

Leggi gli Appunti, controlla l'input e l'ora in cui "digita" l'input. Se gli Appunti hanno lo stesso testo ed è troppo veloce, elimina l'input incollato.


1

@Zain Ali, la tua risposta funziona su API 11. Volevo solo suggerire un modo di fare anche su API 10. Dato che dovevo mantenere l'API del mio progetto su quella versione, giocavo costantemente con le funzioni disponibili in 2.3.3 e ho avuto la possibilità di farlo. Ho condiviso lo snippet di seguito. Ho testato il codice e funzionava per me. Ho fatto questo frammento con urgenza. Sentiti libero di migliorare il codice se ci sono cambiamenti che possono essere fatti.

// A custom TouchListener is being implemented which will clear out the focus 
// and gain the focus for the EditText, in few milliseconds so the selection 
// will be cleared and hence the copy paste option wil not pop up.
// the respective EditText should be set with this listener 
// tmpEditText.setOnTouchListener(new MyTouchListener(tmpEditText, tmpImm));

public class MyTouchListener implements View.OnTouchListener {

    long click = 0;
    EditText mEtView;
    InputMethodManager imm;

    public MyTouchListener(EditText etView, InputMethodManager im) {
        mEtView = etView;
        imm = im;
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {

        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            long curr = System.currentTimeMillis();
            if (click !=0 && ( curr - click) < 30) {

                mEtView.setSelected(false);
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mEtView.setSelected(true);
                        mEtView.requestFocusFromTouch();
                        imm.showSoftInput(mEtView, InputMethodManager.RESULT_SHOWN);
                    }
                },25);

            return true;
            }
            else {
                if (click == 0)
                    click = curr;
                else
                    click = 0;
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mEtView.requestFocusFromTouch();
                        mEtView.requestFocusFromTouch();
                        imm.showSoftInput(mEtView, InputMethodManager.RESULT_SHOWN);
                    }
                },25);
            return true;
            }

        } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
            mEtView.setSelected(false);
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    mEtView.setSelected(true);
                    mEtView.requestFocusFromTouch();
                    mEtView.requestFocusFromTouch();
                    imm.showSoftInput(mEtView, InputMethodManager.RESULT_SHOWN);
                }
            },25);
            return true;
        }
        return false;
    }

1

la soluzione è molto semplice

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

        }
    });
   }
}

--------> preview <---------


1

Prova a seguire la classe custome per copia e incolla precedenti Edittext

public class SegoeUiEditText extends AppCompatEditText {
private final Context context;


@Override
public boolean isSuggestionsEnabled() {
    return false;
}
public SegoeUiEditText(Context context) {
    super(context);
    this.context = context;
    init();
}

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

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


private void setFonts(Context context) {
    this.setTypeface(Typeface.createFromAsset(context.getAssets(), "Fonts/Helvetica-Normal.ttf"));
}

private void init() {

        setTextIsSelectable(false);
        this.setCustomSelectionActionModeCallback(new ActionModeCallbackInterceptor());
        this.setLongClickable(false);

}
@Override
public int getSelectionStart() {

    for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
        if (element.getMethodName().equals("canPaste")) {
            return -1;
        }
    }
    return super.getSelectionStart();
}
/**
 * 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, android.view.ActionMode.Callback {
    private final String TAG = SegoeUiEditText.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) {}

    @Override
    public boolean onCreateActionMode(android.view.ActionMode mode, Menu menu) {
        return false;
    }

    @Override
    public boolean onPrepareActionMode(android.view.ActionMode mode, Menu menu) {
        menu.clear();
        return false;
    }

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

    @Override
    public void onDestroyActionMode(android.view.ActionMode mode) {

    }
}

}


1

Per smartphone con appunti, è possibile prevenire in questo modo.

editText.setFilters(new InputFilter[]{new InputFilter() {
        @Override
        public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
            if (source.length() > 1) {
                return "";
            }  return null;
        }
    }});


0

Ho scoperto che quando si crea un filtro di input per evitare l'inserimento di caratteri indesiderati, incollare tali caratteri nel testo di modifica non ha alcun effetto. Quindi questo tipo di risolve anche il mio problema.



0

La soluzione che ha funzionato per me è stata quella di creare Edittext personalizzati e sovrascrivere il seguente metodo:

public class MyEditText extends EditText {

private int mPreviousCursorPosition;

@Override
protected void onSelectionChanged(int selStart, int selEnd) {
    CharSequence text = getText();
    if (text != null) {
        if (selStart != selEnd) {
            setSelection(mPreviousCursorPosition, mPreviousCursorPosition);
            return;
        }
    }
    mPreviousCursorPosition = selStart;
    super.onSelectionChanged(selStart, selEnd);
}

}


0

Prova ad usare.

myEditext.setCursorVisible(false);

       myEditext.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;
        }
    });

0

Chi è alla ricerca di una soluzione in Kotlin usa la classe seguente come widget personalizzato e la usa in XML.

classe SecureEditText: TextInputEditText {

/** 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 fun isSuggestionsEnabled(): Boolean {
    return false
}

override fun getSelectionStart(): Int {
    for (element in Thread.currentThread().stackTrace) {
        if (element.methodName == "canPaste") {
            return -1
        }
    }
    return super.getSelectionStart()
}

public override fun onSelectionChanged(start: Int, end: Int) {

    val text = text
    if (text != null) {
        if (start != text.length || end != text.length) {
            setSelection(text.length, text.length)
            return
        }
    }

    super.onSelectionChanged(start, end)
}

companion object {
    private val EDITTEXT_ATTRIBUTE_COPY_AND_PASTE = "isCopyPasteDisabled"
    private val PACKAGE_NAME = "http://schemas.android.com/apk/res-auto"
}

constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
    disableCopyAndPaste(context, attrs)
}

/**
 * Disable Copy and Paste functionality on EditText
 *
 * @param context Context object
 * @param attrs   AttributeSet Object
 */
private fun disableCopyAndPaste(context: Context, attrs: AttributeSet) {
    val isDisableCopyAndPaste = attrs.getAttributeBooleanValue(
        PACKAGE_NAME,
        EDITTEXT_ATTRIBUTE_COPY_AND_PASTE, true
    )
    if (isDisableCopyAndPaste && !isInEditMode()) {
        val inputMethodManager =
            context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        this.setLongClickable(false)
        this.setOnTouchListener(BlockContextMenuTouchListener(inputMethodManager))
    }
}

/**
 * Perform Focus Enabling Task to the widget with the help of handler object
 * with some delay
 * @param inputMethodManager is used to show the key board
 */
private fun performHandlerAction(inputMethodManager: InputMethodManager) {
    val postDelayedIntervalTime: Long = 25
    Handler().postDelayed(Runnable {
        this@SecureEditText.setSelected(true)
        this@SecureEditText.requestFocusFromTouch()
        inputMethodManager.showSoftInput(
            this@SecureEditText,
            InputMethodManager.RESULT_SHOWN
        )
    }, postDelayedIntervalTime)
}

/**
 * Class to Block Context Menu on double Tap
 * A custom TouchListener is being implemented which will clear out the focus
 * and gain the focus for the EditText, in few milliseconds so the selection
 * will be cleared and hence the copy paste option wil not pop up.
 * the respective EditText should be set with this listener
 *
 * @param inputMethodManager is used to show the key board
 */
private inner class BlockContextMenuTouchListener internal constructor(private val inputMethodManager: InputMethodManager) :
    View.OnTouchListener {
    private var lastTapTime: Long = 0
    val TIME_INTERVAL_BETWEEN_DOUBLE_TAP = 30
    override fun onTouch(v: View, event: MotionEvent): Boolean {
        if (event.getAction() === MotionEvent.ACTION_DOWN) {
            val currentTapTime = System.currentTimeMillis()
            if (lastTapTime != 0L && currentTapTime - lastTapTime < TIME_INTERVAL_BETWEEN_DOUBLE_TAP) {
                this@SecureEditText.setSelected(false)
                performHandlerAction(inputMethodManager)
                return true
            } else {
                if (lastTapTime == 0L) {
                    lastTapTime = currentTapTime
                } else {
                    lastTapTime = 0
                }
                performHandlerAction(inputMethodManager)
                return true
            }
        } else if (event.getAction() === MotionEvent.ACTION_MOVE) {
            this@SecureEditText.setSelected(false)
            performHandlerAction(inputMethodManager)
        }
        return false
    }
}

}


0

ho aggiunto la funzione di estensione in linguaggio Kotlin :

fun EditText.disableTextSelection() {
    this.setCustomSelectionActionModeCallback(object : android.view.ActionMode.Callback {
        override fun onActionItemClicked(mode: android.view.ActionMode?, item: MenuItem?): Boolean {
            return false
        }
        override fun onCreateActionMode(mode: android.view.ActionMode?, menu: Menu?): Boolean {
            return false
        }
        override fun onPrepareActionMode(mode: android.view.ActionMode?, menu: Menu?): Boolean {
            return false
        }
        override fun onDestroyActionMode(mode: android.view.ActionMode?) {
        }
    })
}

puoi usarlo in questo modo:

edit_text.disableTextSelection()

anche aggiunto sotto la riga nel tuo XML:

                android:longClickable="false"
                android:textIsSelectable="false"
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.