Mon objectif est d'avoir un EditText
qui n'a pas de fonctionnalités de fantaisie, juste le gestionnaire de sélection de texte pour déplacer le curseur plus facilement - donc pas de menus contextuels ou de fenêtres contextuelles.
J'ai désactivé l'apparence de la barre d'action de la fonction d'édition de texte (copier/coller, etc.) en consommant l'événement de rappel ActionMode, conformément à cette solution .
La poignée de sélection centrale du texte du milieu (voir l'image ci-dessous) apparaît toujours lorsque du texte existe dans le champ et qu'un clic se produit dans le texte. Génial! Je veux garder ce comportement. Ce que je NE VEUX PAS, c'est que le menu "PASTE" apparaisse lorsque l'on clique sur la poignée de sélection de texte elle-même.
J'ai également désactivé la saisie d'un clic long pour EditText en définissant Android:longClickable="false"
dans les styles XML. La désactivation du clic long empêche le menu "Coller/Remplacer" d'apparaître lorsque la souris est cliquée et maintenue (c.-à-d. Touche longue), mais lorsque la souris est cliquée (touche unique) dans le texte, la poignée de sélection de texte apparaît et lorsque le la poignée de sélection de texte elle-même est cliquée, puis l'option de menu "coller" apparaît (lorsqu'il y a du texte dans le presse-papiers). C'est ce que j'essaie d'empêcher.
D'après ce que je peux voir de la source, le ActionPopupWindow
est ce qui apparaît avec les options PASTE/REPLACE. ActionPopupWindow est une variable protégée (mActionPopupWindow) dans la classe abstraite privée HandleView dans la classe publique Android.widget.Editor ...
À moins de désactiver le service de presse-papiers ou de modifier le Android code source, existe-t-il un moyen d'empêcher cela de s'afficher? J'ai essayé de définir un nouveau style pour Android:textSelectHandleWindowStyle
, Et mettre Android:visibility
à gone
, mais cela n'a pas fonctionné (l'application s'est figée pendant un certain temps alors qu'elle aurait autrement été affichée).
Solution: remplacez isSuggestionsEnabled
et canPaste
dans EditText
.
Pour la solution rapide, copiez la classe ci-dessous - cette classe remplace la classe EditText
et bloque tous les événements en conséquence.
Pour les détails granuleux, continuez à lire.
La solution consiste à empêcher le menu PASTE/REPLACE d'apparaître dans la méthode show()
de la classe (non documentée) Android.widget.Editor
. Avant que le menu n'apparaisse, une vérification est effectuée sur if (!canPaste && !canSuggest) return;
. Les deux méthodes utilisées comme base pour définir ces variables se trouvent toutes deux dans la classe EditText
:
isSuggestionsEnabled()
est public , et peut donc être remplacé.canPaste()
ne l'est pas, et doit donc être masqué par en introduisant une fonction du même nom dans la classe dérivée.Donc, incorporer ces mises à jour dans une classe qui a également le setCustomSelectionActionModeCallback , et le clic long désactivé , voici la classe complète pour empêcher toute modification (mais toujours afficher le - gestionnaire de sélection de texte ) pour contrôler le curseur:
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) {}
}
}
J'ai testé cela dans Android v4.4.2 et v4.4.3.
ou utilisez simplement
yourEditText.setLongClickable(false);
OU en XML
Android:longClickable="false"
Mise à jour
En fait, l'utilisateur veut désactiver la poignée de sélection de texte elle-même
1. Créez une forme (handle.xml)
<shape xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:shape="rectangle" >
<size
Android:height="0dp"
Android:width="0dp" />
</shape>
2. Dans votre EditText
Android:textSelectHandle="@drawable/handle"
Voici un hack pour désactiver la popup "coller". Vous devez remplacer la méthode EditText
:
@Override
public int getSelectionStart() {
for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
if (element.getMethodName().equals("canPaste")) {
return -1;
}
}
return super.getSelectionStart();
}
Cette solution fonctionne sur les nouvelles versions de Android également, contrairement à la réponse acceptée.
Je ne trouve pas un moyen de masquer le menu contextuel, mais vous pouvez désactiver le collage si l'utilisateur tape sur le menu
Créez un EditText
personnalisé et remplacez la méthode onTextContextMenuItem
et retournez false pour Android.R.id.paste
et Android.R.id.pasteAsPlainText
ID de menu.
@Override
public boolean onTextContextMenuItem(int id) {
switch (id){
case Android.R.id.paste:
case Android.R.id.pasteAsPlainText:
return false;
}
return super.onTextContextMenuItem(id);
}
Trouvé une autre solution lorsque la vue bleue (contrôleur d'insertion) n'apparaît pas du tout. J'ai utilisé la réflexion pour définir le champ booléen cible de la classe Editor. Regardez Android.widget.Editor et Android.widget.TextView pour plus de détails.
Ajoutez le code suivant dans votre EditText personnalisé (avec tout le code précédent dans cette rubrique):
@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
}
}
De plus, vous pouvez peut-être trouver le meilleur endroit que onTouch () pour appeler la méthode cible.
Testé sur Android 5.1
Si vous devez supprimer la suggestion COLLER, videz le presse-papiers avant le clic long.
//class
ClipboardManager clipboard;
//oncreate
clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("","");
clipboard.setPrimaryClip(clip);
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.
Remplacez simplement une méthode:
@Override
protected MovementMethod getDefaultMovementMethod() {
// we don't need arrow key, return null will also disable the copy/paste/cut pop-up menu.
return null;
}
J'ai trouvé un moyen simple mais fiable. L'idée est de consommer l'événement tactile, pour éviter que l'événement tactile n'atteigne le code par défaut.
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);
}
Remarque: le curseur clignotant s'affiche toujours à la fin du texte. Juste que la capture d'écran ne peut pas la capturer.
Aucune des solutions ci-dessus n'a fonctionné pour moi. J'ai réussi à faire ma solution (explication après), qui a désactivé tout collage sur le EditText tout en maintenant toutes les autres opérations valides.
Principalement, vous devez remplacer cette méthode sur votre implémentation de EditText:
@Override
public boolean onTextContextMenuItem (int id) {
if (id == Android.R.id.paste) return false;
return super.onTextContextMenuItem(id);
}
Ainsi, en examinant le code EditText, après toutes les vérifications, le collage (et toutes les actions ContextMenu
sur le EditText) se produisent à une méthode appelée 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 vous remarquez, le collage ne se produira que lorsque id == ID_PASTE
, donc, encore une fois, en regardant le code EditText:
static final int ID_PASTE = Android.R.id.paste;