Como desativar copiar / colar de / para EditText


131

No meu aplicativo, há uma tela de registro, na qual eu não quero que o usuário possa copiar / colar texto no EditTextcampo. Eu configurei um onLongClickListenerem cada um EditTextpara que o menu de contexto mostrando copiar / colar / método de entrada e outras opções não apareça. Portanto, o usuário não poderá copiar / colar nos campos Editar.

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

Mas o problema surge se o usuário tiver ativado um teclado de terceiros que não seja o padrão do Android, que pode ter um botão para copiar / colar ou que pode exibir o mesmo menu de contexto. Então, como desativo copiar / colar nesse cenário?

Informe-me se há outras maneiras de copiar / colar também. (e possivelmente como desativá-los)

Qualquer ajuda seria apreciada.


Se a operação "colar" vier de um IME, você não terá uma maneira padrão de distingui-lo das teclas normais. Uma idéia a tentar é medir o tempo entre a chegada de cada personagem e, se o tempo for muito curto, os caracteres serão provenientes de uma operação de "colar".
BitBank 13/11/11

parece ser uma solução suja! vale uma olhada embora.
RDroid 14/11

1
use android: longClickable = "false"
Azay Gupta

Respostas:


112

Se você estiver usando o nível 11 ou superior da API, poderá parar a exibição dos menus de copiar, colar, recortar e de contexto personalizado.

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

Retornar false de onCreateActionMode (ActionMode, Menu) impedirá que o modo de ação seja iniciado (ações Selecionar Tudo, Recortar, Copiar e Colar).


1
e quanto ao nível da API abaixo de 13?
8133 Jonathan

1
Não entendo tanto de comentários, esse exemplo funciona api11 +, pré-api11 não houve copiar e colar IIRC
scottyab

28
Não funciona para mim. O botão Paste será exibido em caso de toque no indicador azul do cursor.
vazio

8
Também não está funcionando para mim. Em Tocar duas vezes, o menu copiar e colar está sendo exibido.
Android Killer

isso não funciona mais no Android 6.0, verifique esta resposta stackoverflow.com/questions/27869983/…
has19

132

O melhor método é usar:

etUsername.setLongClickable(false);

58
Ou, apenas no xml android:longClickable="false":)
Lomza

19
O botão Colar aparecerá no caso de tocar no indicador azul do cursor.
vazio

16
Isso certamente impedirá que a exibição seja clicada por muito tempo, mas os controles de edição também podem ser solicitados tocando duas vezes no texto, o que significa que esta solução não está completa. Tenha isso em mente para seus propósitos.
Kevin Grant

1
Além disso, os atalhos de teclado ainda podem funcionar (Ctrl + C) com teclados externos.
Oleg Vaskevich

Isso não funciona no Ice Cream Sandwich, porque as opções da área de transferência podem ser abertas com um toque duplo no texto e um toque longo.
Paul Wintz

44

Você pode fazer isso desativando a pressão prolongada do EditText

Para implementá-lo, basta adicionar a seguinte linha no xml -

android:longClickable="false"

6
O problema foi que o usuário do meu aplicativo possui um teclado de terceiros com um botão copiar e colar.
RDroid 16/04

3
Outro problema é que você pode selecionar o texto por duplo toque e mostra copiar / colar novamente
Nikola

37

Consigo desativar a funcionalidade copiar e colar com o seguinte:

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

Espero que funcione para você ;-)


Essa é exatamente a mesma solução com a qual eu baseei nas outras respostas acima. Este deve ser marcado como a solução correta, uma vez que lida com os casos de ponta os outros não
Andrew Hoefling

2
Esta opção bloqueia a cópia, mas você ainda pode colar clicando no cursor.
Mehul Kanzariya

12

aqui está a melhor maneira de desativar a cópia recortada colar do trabalho editText em todas as versões

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

Isso funcionou para mim, eu só tive que adicionar @TargetApi (Build.VERSION_CODES.HONEYCOMB)
Sheepdogsheep

11

Além das soluções setCustomSelectionActionModeCallback e desativadas , é necessário impedir que os menus PASTE / REPLACE apareçam quando o identificador de seleção de texto é clicado, conforme a imagem abaixo:

Alça de seleção de texto com menu colar

A solução está em impedir que o menu PASTE / REPLACE apareça no show()método da android.widget.Editorclasse (não documentada) . Antes que o menu apareça, é feita uma verificação para if (!canPaste && !canSuggest) return;. Os dois métodos usados ​​como base para definir essas variáveis ​​estão na EditTextclasse:

Uma resposta mais completa está disponível aqui .


Esta é a solução correta e completa
FireZenk

Em alguns dispositivos, em vez da opção Colar área de transferência está visível, atua apenas como colar. Eu verifiquei os links, mas sou capaz de impedir a colar, mas não a área de transferência. qualquer ideia ?
Richa

10

Solução 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?) {}
    }
}

Então você pode simplesmente chamar esse método no seu TextView:

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

1
Olá, estou usando essa abordagem, mas estou recebendo um Type mismatcherro com esta descrição Required:ActionMode.Callback! Found: desta parte object: ActionMode.Callback. Alguma idéia de por que pode não estar funcionando?
Abdul Mateen

8

Usando outras soluções, a API 26 (Oreo) ainda estava mostrando a alça do cursor com um único toque no texto digitado e, em seguida, o menu pode ser mostrado. Somente combinações de soluções podem resolver meu 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 você não deseja desativar o clique longo, porque precisa executar algumas funcionalidades no clique longo do que retornar true é uma opção melhor para fazê-lo.

O seu clique longo no edittext será assim.

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

De acordo com a documentação, Returning "True" indicará que o clique longo foi manipulado, não sendo necessário executar operações padrão.

Eu testei isso nos níveis 16, 22 e 25 da API. Está funcionando bem para mim. Espero que isso ajude.


1
Um bom. Como alternativa, basta definir o android:longClickable="false"XML
Alex Semeniuk


3

Aqui está um hack para desativar o pop-up "colar". Você precisa substituir o EditTextmétodo:

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

Semelhante pode ser feito para as outras ações.


você pode dizer para a área de transferência desativar
Richa

3

Eu testei esta solução e isso funciona

    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

Leia a área de transferência, verifique a entrada e a hora em que a entrada é "digitada". Se a área de transferência tiver o mesmo texto e for muito rápida, exclua a entrada colada.


1

@Zain Ali, sua resposta funciona na API 11. Eu só queria sugerir uma maneira de participar da API 10. Como eu tinha que manter minha API do projeto nessa versão, eu estava constantemente jogando com as funções disponíveis na 2.3.3 e tive a possibilidade de fazê-lo. Compartilhei o trecho abaixo. Testei o código e ele estava funcionando para mim. Eu fiz esse trecho com urgência. Sinta-se livre para melhorar o código se houver alguma alteração que possa ser feita.

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

A solução é muito simples

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

        }
    });
   }
}

--------> visualização <---------


1

Tente Seguir a classe de cliente para copiar e colar em 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

Para smartphone com prancheta, é possível evitar assim.

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

Descobri que, quando você cria um filtro de entrada para evitar a entrada de caracteres indesejados, colar esses caracteres no texto de edição não tem efeito. Então isso também resolve meu problema.



0

A solução que funcionou para mim foi criar o Edittext personalizado e substituir o seguinte método:

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

Tente usar.

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

Quem está procurando uma solução no Kotlin, usa a classe abaixo como um widget personalizado e usa-o no 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

eu adicionei a função de extensão na linguagem 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?) {
        }
    })
}

você pode usá-lo assim:

edit_text.disableTextSelection()

também adicionado abaixo da linha no seu xml:

                android:longClickable="false"
                android:textIsSelectable="false"
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.