android - varias - Editar texto: Deshabilitar el menú emergente Pegar/Reemplazar en el evento de clic del controlador de selección de texto
como reemplazar palabras en word mac (11)
Mi objetivo es tener un texto de EditText
que no tenga funciones sofisticadas, solo el EditText
selección de texto para mover el cursor más fácilmente, por lo que no hay menús contextuales ni ventanas emergentes.
He deshabilitado la apariencia de la barra de acción de la función de edición de texto (copiar / pegar, etc.) al consumir el evento de devolución de llamada ActionMode, según esta solución .
La manija de selección de texto del medio medio (ver imagen abajo) aún aparece cuando existe texto en el campo y se produce un clic dentro del texto. ¡Genial! Quiero mantener este comportamiento. Lo que NO QUIERO es que aparezca el menú "PEGAR" cuando se hace clic en el selector de texto.
También deshabilité la entrada de clic largo para EditText configurando android:longClickable="false"
en los estilos XML. La desactivación del clic prolongado evita que aparezca el menú "Pegar / Reemplazar" cuando se hace clic y se mantiene presionado el mouse (es decir, un toque prolongado); sin embargo, cuando se hace clic con el mouse (toque sencillo) dentro del texto, aparece el control de selección de texto y cuando aparece se hace clic en el selector de selección de texto, luego 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 en la fuente, el 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 ...
Aparte de desactivar el servicio del portapapeles o editar el código fuente de Android, ¿hay alguna forma de evitar que se muestre? Intenté definir un nuevo estilo para android:textSelectHandleWindowStyle
, y configurar android:visibility
gone
, pero no funcionó (la aplicación se congeló por un tiempo cuando de lo contrario se mostraría).
Aquí hay un truco para deshabilitar la ventana emergente "pegar". 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 también funciona en las versiones más recientes de Android, a diferencia de la respuesta aceptada.
Encontré una manera simple pero confiable. La idea es consumir el evento táctil para evitar que el evento táctil alcance el código predeterminado.
- Para deshabilitar copiar / pegar ventana emergente.
- Para deshabilitar el controlador de selección de texto.
- Todavía mostrando el cursor al final del texto.
- Todavía 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);
}
Tenga en cuenta que el cursor parpadeante todavía se muestra al final del texto. Solo que la captura de pantalla no logra capturarlo.
Ninguna de las soluciones anteriores funcionó para mí. Me las arreglé para hacer mi solución (explicación después), que deshabilitó pegar cualquier cosa en el EditText mientras mantenía todas las demás operaciones válidas.
Principalmente, debe anular este método en su implementación de EditText:
@Override
public boolean onTextContextMenuItem (int id) {
if (id == android.R.id.paste) return false;
return super.onTextContextMenuItem(id);
}
Por lo tanto, al investigar el código EditText, después de todas las comprobaciones, pegue (y todas las acciones de ContextMenu
en el EditText) 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 se da cuenta, el pegado solo ocurrirá cuando id == ID_PASTE
, así que, nuevamente, mirando el código EditText:
static final int ID_PASTE = android.R.id.paste;
No encuentro una forma de ocultar el menú emergente, pero puede deshabilitarlo de pegar si el usuario toca en el menú
Cree un EditText
personalizado y anule el método onTextContextMenuItem
y devuelva false para los identificadores de menú de android.R.id.paste
y android.R.id.pasteAsPlainText
.
@Override
public boolean onTextContextMenuItem(int id) {
switch (id){
case android.R.id.paste:
case android.R.id.pasteAsPlainText:
return false;
}
return super.onTextContextMenuItem(id);
}
Puedes usar 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;
}
});
}
La devolución de falso desde onCreateActionMode
deshabilitará las opciones de cortar, copiar y pegar en el nivel de API superior a 11.
Se encontró otra solución cuando la vista azul (controlador de inserción) no aparece en absoluto. Utilicé la reflexión para establecer el campo booleano de destino de la clase Editor. Mira el android.widget.Editor y android.widget.TextView para más detalles.
Agregue el siguiente código en su EditText 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
}
}
Además, quizás pueda encontrar el mejor lugar que onTouch () para llamar al método de destino.
Probado en Android 5.1
Si necesita eliminar la sugerencia de PASTE, borre el portapapeles antes de hacer un clic largo.
//class
ClipboardManager clipboard;
//oncreate
clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("","");
clipboard.setPrimaryClip(clip);
Simplemente anula un método:
@Override
protected MovementMethod getDefaultMovementMethod() {
// we don''t need arrow key, return null will also disable the copy/paste/cut pop-up menu.
return null;
}
o simplemente usar
yourEditText.setLongClickable(false);
O en XML
android:longClickable="false"
Actualizar
En realidad, el usuario quiere deshabilitar el propio selector de texto.
1. Crea 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 tu EditText
android:textSelectHandle="@drawable/handle"
Solución: isSuggestionsEnabled
y canPaste
en EditText
.
Para la solución rápida, copie la clase a continuación: esta clase anula la clase EditText
y bloquea todos los eventos en consecuencia.
Para los detalles arenosos, sigue leyendo.
La solución radica en evitar que el menú PEGAR / REEMPLAZAR aparezca en el método show()
de la clase (no documentada) android.widget.Editor
. Antes de que aparezca el menú, se realiza una comprobación de if (!canPaste && !canSuggest) return;
. Los dos métodos que se utilizan como base para establecer estas variables están en la clase EditText
:
-
isSuggestionsEnabled()
es public y, por lo tanto, puede ser anulado. -
canPaste()
no lo es, y por lo tanto debe ocultarse introduciendo una función del mismo nombre en la clase derivada.
Así que incorporando estas actualizaciones en una clase que también tiene setCustomSelectionActionModeCallback , y el clic prolongado desactivado , aquí está la clase completa para evitar toda edición (pero aún 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.
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.