Desactivar el menú contextual de EditText

Estoy haciendo un EditText vertical para mongol tradicional. Lo he implementado exitosamente al EditText un ViewGroup ligeramente modificado dentro de un ViewGroup rotado. Necesito crear un menú contextual completamente personalizado porque el sistema no admite texto vertical y tampoco se rota cuando se gira el grupo de ViewGroup . Por lo tanto, quiero deshabilitar el menú contextual del sistema por completo.

Tenga en cuenta que esto es diferente a estas preguntas que simplemente intentan deshabilitar copiar / pegar / etc .:

  • Cómo deshabilitar copiar / pegar desde / hacia EditText
  • EditText: deshabilita la ventana emergente del menú Pegar / Reemplazar en el evento de clic del controlador de selección de texto
  • cómo deshabilitar la opción pegar en android EditText
  • Android: Cómo deshabilitar TOTALMENTE la función copiar y pegar en Edittext

Aunque no aparece el menú contextual en el simulador, aparece en mi teléfono Android 5.0.2 Xiaomi.

Yo he tratado:

  • la “solución” setCustomSelectionActionModeCallback
  • setLongClickable(false); “solución”
  • la “solución” onTouchEvent

Estoy abierto a hacks, pero lo necesito para trabajar de manera consistente en todos los dispositivos. Mark Murphy (un chico de los comunes) escribió hace tiempo en respuesta a otro usuario que intenta hacer algo similar:

Sospecho que incluso si se te ocurre una respuesta, no funcionará en todos los dispositivos. Los fabricantes de dispositivos han tenido la tendencia de desplegar su propio “menú de contexto” para EditText, derrotando los bashs de los desarrolladores de agregar elementos en ese menú contextual. Mi suposición es que tratar de bloquear ese menú contextual tendrá resultados similares.

¿No tengo suerte?

Lo único que se me ocurre ahora es reescribir completamente TextView y EditText desde cero (bueno, modificando la fuente de Android). Conozco a alguien más que hizo algo similar, pero su código no es de código abierto. Antes de dar este gran paso, quiero intentar pedir una solución más simple aquí en Stack Overflow.

Actualización: he intentado modificar el código fuente de TextView durante los últimos dos días y parece un proyecto de 6 meses. Es una masa de clases interrelacionadas. Necesito otra solución, pero estoy sin ideas.

MVCE

Esta es la manera más simple que se me ocurre para recrear el problema. No hay nada necesario de mi EditText personalizado. El diseño tiene un solo EditText creado reemplazando el proyecto predeterminado Hello World’s TextView . Cambié la API mínima a 11 para evitar tener que lidiar con métodos obsoletos.

 public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); EditText editText = (EditText) findViewById(R.id.edit_text); editText.setCustomSelectionActionModeCallback(new ActionMode.Callback() { @Override public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { return false; } @Override public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { return false; } @Override public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) { return false; } @Override public void onDestroyActionMode(ActionMode actionMode) { } }); } } 

El menú contextual en el simulador (que ejecuta la API 24) aún se muestra cuando hago clic en el controlador del cursor (pero no en un clic largo o doble clic). Aquí hay una imagen:

enter image description here

En mi teléfono Xiaomi MIUI con Android 5.0, obtengo el menú contextual en todas las situaciones (clic del cursor, clic largo, doble clic).

Actualizar

La solución de Aritra Roy está funcionando en el simulador, en algunos otros dispositivos que ha probado y en mi dispositivo. He aceptado su respuesta porque resuelve mi problema original. El único efecto secundario negativo es que la selección de texto también está deshabilitada.

Hay tres cosas que debes hacer.

PASO 1

Puede deshabilitar los menús contextuales al devolver falso de estos métodos,

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

PASO 2

También es necesario desactivar el clic largo en EditText.

 mEditText.setLongClickable(false); 

o haciendo esto, android:longClickable="false" en XML.

PASO 3

Ahora, debe evitar que los menús aparezcan cuando se hace clic en los controles. La solución es simple,

1) Extienda la clase EditText ,

2) Anular isSuggestionsEnabled() y devolver false

3) Crea un método canPaste() y devuelve false . Este es un método escondido.

SOLUCIÓN RÁPIDA

Si no quiere hacer todo esto manualmente. Aquí hay una clase personalizada de EditText que puede usar para hacer esto rápidamente. Pero aún así te recomiendo que sigas los pasos una vez para entender cómo funcionan las cosas.

 public class MenuHidingEditText extends EditText { private final Context mContext; public MenuHidingEditText(Context context) { super(context); this.mContext = context; blockContextMenu(); } public MenuHidingEditText(Context context, AttributeSet attrs) { super(context, attrs); this.mContext = context; blockContextMenu(); } public MenuHidingEditText(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); this.mContext = context; blockContextMenu(); } private void blockContextMenu() { this.setCustomSelectionActionModeCallback(new BlockedActionModeCallback()); this.setLongClickable(false); this.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { MenuHidingEditText.this.clearFocus(); return false; } }); } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { // setInsertionDisabled when user touches the view this.setInsertionDisabled(); } return super.onTouchEvent(event); } 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) { } } } 

He hecho este código para EditText , y funcionó bien para un problema así.

 try { edtName.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { edtName.setSelection(0); } }); edtName.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { return true; } }); edtName.setCustomSelectionActionModeCallback(new ActionMode.Callback() { @Override public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { return false; } @Override public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { return false; } @Override public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) { return false; } @Override public void onDestroyActionMode(ActionMode actionMode) { } }); } catch (Exception e) { e.printStackTrace(); } 
 mEditText.setLongClickable(false); 

Es la forma más sencilla de desactivar el texto de edición.

la solución es muy simple

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

enter image description here

Así es como se bloquea el menú copiar pegar para que no aparezca de ninguna manera, forma o forma. Este error realmente me volvió loco, y como con cualquier error de Samsung, usted sabe que está en su código, pero también sabe que no lo arreglarán en el corto plazo. De todos modos, aquí está la pared de la maravilla …

  1. Compruebe si Android.Build.Model.toLowerCase (). StartsWith (‘sm-g930’). No haga coincidir toda la cadena, la última letra es un identificador de versión menor. Almacé este booleano en la variable shouldBlockCopyPaste que aparece más adelante.

  2. Si coincide, quiere bloquear la visualización del menú de copiar y pegar. Así es como REALMENTE LO HACES!

Sobreescriba estas 2 funciones, notará mi shouldBlockCopyPaste boolean, esto es para que otros dispositivos no se bloqueen.

  @Override public ActionMode StartActionMode (ActionMode.Callback callback){ if (shouldBlockCopyPaste) { return null; } else { return super.StartActionMode(callback); } } @Override public ActionMode StartActionMode (ActionMode.Callback callback, int type){ if (shouldBlockCopyPaste) { return null; } else { return super.StartActionMode(callback, type); } } 

prueba esto

 mEditText.setClickable(false); mEditText.setEnabled(false); 

ACTUALIZAR

Pruebe esta solución ampliando Edittext,

 import android.content.Context; import android.util.AttributeSet; import android.view.ActionMode; import android.view.Menu; import android.view.MenuItem; import android.widget.EditText; 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) {} } } 

Referencia: https://stackoverflow.com/a/28893714/5870896