EditText: Desactivar el menú emergente de Pegar / Reemplazar en el evento de clic del controlador de selección de texto

Mi objetivo es tener un EditText que no tiene características de fantasía, sólo el EditText selección de texto para mover el cursor más fácilmente – por lo que no hay menús de contexto o pop-ups.

He deshabilitado la apariencia de la barra de acción de la función de edición de texto (copiar / pegar, etc.) consumiendo el evento de devolución de llamada ActionMode, según esta solución .

La palanca de selección media de medio texto (véase la imagen de abajo) sigue apareciendo cuando existe texto en el campo y se produce un clic dentro del texto. ¡Estupendo! Quiero mantener este comportamiento. Lo que NO quiero es que aparezca el menú "PASTA" cuando se hace clic en el selector de selección de texto.

Asistente de selección de texto con menú pegar

También he inhabilitado la entrada del largo-tecleo para el EditText fijando android:longClickable="false" en los estilos XML. Desactivar el clic largo evita que aparezca el menú "Pegar / Reemplazar" cuando se hace clic y se mantiene presionado (es decir, toque largo), sin embargo, cuando se hace clic con el ratón (solo toque) dentro del texto, aparece el identificador de selección de texto y Se hace clic en el selector de selección de texto y, a continuación, aparece la opción de menú "pegar" (cuando hay texto en el portapapeles). Esto es lo que estoy tratando de prevenir.

Por lo que puedo ver de la fuente, ActionPopupWindow es lo que aparece con las opciones PASTE / REPLACE. ActionPopupWindow es una variable protegida (mActionPopupWindow) en la clase abstracta privada HandleView dentro de la clase pública android.widget.Editor …

A falta de deshabilitar el servicio del portapapeles o editar el código fuente de Android, ¿hay alguna manera de evitar que se muestre? Traté de definir un nuevo estilo para android:textSelectHandleWindowStyle , y establecer android: visibilidad to ido `, pero no funcionó (la aplicación se congeló durante un tiempo cuando de lo contrario se mostraría).

Solución: isSuggestionsEnabled y canPaste en EditText .

Para la solución rápida, copie la clase a continuación: esta clase reemplaza a la clase EditText y bloquea todos los sucesos en consecuencia.

Para los detalles arenoso, sigue leyendo.

La solución consiste en evitar que el menú PASTE / REPLACE aparezca en el método show() de la clase android.widget.Editor (no documentada). Antes de que aparezca el menú, se realizará una comprobación para if (!canPaste && !canSuggest) return; . Los dos métodos que se utilizan como base para establecer estas variables están ambos en la clase EditText :

  • isSuggestionsEnabled() es pública y, por lo tanto, puede ser anulada.
  • canPaste() no es, y por lo tanto debe ser ocultado mediante la introducción de una función del mismo nombre en la clase derivada.

Así que incorporando estas actualizaciones en una clase que también tiene el setCustomSelectionActionModeCallback , y el deshabilitado haga clic en largo , aquí es la clase completa para evitar toda la edición (pero todavía mostrar el controlador de selección de texto ) para controlar el cursor:

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

He probado esto en Android v4.4.2 y v4.4.3.

O simplemente usa

 yourEditText.setLongClickable(false); 

O en XML

 android:longClickable="false" 

Actualizar

En realidad, el usuario desea desactivar el control de selección de texto sí mismo

1. Cree una forma (handle.xml)

  <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <size android:height="0dp" android:width="0dp" /> </shape> 

2. En su EditText

  android:textSelectHandle="@drawable/handle" 

Encontré otra solución cuando la vista azul (controlador de inserción) no apareció en absoluto. Utilicé la reflexión para fijar el campo booleano de la clase del redactor. Mira el android.widget.Editor y android.widget.TextView para más detalles.

Agregue el código siguiente en su EditarTexto personalizado (con todo el código anterior en este tema):

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

También, tal vez usted puede encontrar el lugar mejor que onTouch () para llamar al método de destino.

Probado en Android 5.1

No encuentro una forma de ocultar el menú emergente, pero se puede desactivar de pegar si el usuario pulsa en el menú

Cree un EditText personalizado y anule el método onTextContextMenuItem y devuelva false para android.R.id.paste y android.R.id.pasteAsPlainText id del menú.

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

Aquí está un hack para deshabilitar "pegar" popup. Tienes que anular el método EditText :

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

Esta solución funciona en las versiones más recientes de Android, así, a diferencia de la respuesta aceptada.

 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. 

Ninguna de las soluciones anteriores funcionó para mí. He logrado hacer mi solución (explicación después), que deshabilitado pegar cualquier cosa en el EditText, manteniendo todas las demás operaciones válidas.
Principalmente, tiene que anular este método en la implementación de EditText:

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

Así que investigar el código EditText, después de todas las comprobaciones, pegar (y todas las acciones ContextMenu en el EditText) suceden en un método llamado 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 observa, el pegado sólo se producirá cuando id == ID_PASTE , por lo que, de nuevo, mirando el código EditText:

 static final int ID_PASTE = android.R.id.paste; 

Si necesita eliminar la sugerencia de PASTE, borre el portapapeles antes del clic largo.

 //class ClipboardManager clipboard; //oncreate clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); ClipData clip = ClipData.newPlainText("",""); clipboard.setPrimaryClip(clip); 

Encontré una manera simple pero confiable. La idea es consumir lejos el acontecimiento del tacto, para prevenir el alcance del acontecimiento del tacto que subraya el código del defecto.

  1. Para deshabilitar el popup de copiar / pegar.
  2. Para deshabilitar el controlador de selección de texto.
  3. Sigue mostrando el cursor al final del texto.
  4. Sigue mostrando el teclado.

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

Introduzca aquí la descripción de la imagen

Nota, el cursor parpadeante sigue mostrándose al final del texto. Sólo que la captura de pantalla no puede capturarlo.

Puede utilizar este código:

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

Devolver false de onCreateActionMode deshabilitará las opciones cortar, copiar y pegar en el nivel API superior a 11.

  • ¿Cómo iniciar una nueva actividad desde lockscreen?
  • Widget de Android no se está actualizando
  • Cómo agregar widgets múltiples en una aplicación?
  • Actualización de Android Widget desde un clic de botón
  • Cómo configurar correctamente un icono de widget grande en android
  • Ancho más pequeño para Galaxy S y Galaxy S2
  • ¿Cómo usar una tipografía personalizada en un widget?
  • Estilos de widgets personalizados de Android: cómo colocarlos en un espacio de nombres?
  • ¿Cómo eliminar el widget cuando la aplicación se desinstala en Android?
  • Widget android con varios botones
  • Cómo hacer un GridLayout ajustar el tamaño de la pantalla
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.