EditText:在文本选择处理程序单击事件上禁用 Paste/Replace 菜单 pop-up
EditText: Disable Paste/Replace menu pop-up on Text Selection Handler click event
我的目标是 EditText
没有花哨的功能,只有文本 Selection 处理程序可以更轻松地移动光标 -- 因此没有上下文菜单或 pop-ups .
根据 this solution.
,我通过使用 ActionMode Callback 事件禁用了文本编辑功能操作栏(copy/Paste 等)的外观
中间的中间文本 Select 句柄(见下图)在字段中存在文本并且在文本中发生单击时仍然出现。伟大的!我想保持这种行为。我不想要的是 "PASTE" 菜单在单击文本 Select 句柄本身时出现。
我还通过在样式 XML 中设置 android:longClickable="false"
禁用了 EditText 的 long-click 输入。禁用长按可防止在单击并按住鼠标(即长按)时显示 "Paste/Replace" 菜单,但是当在文本中单击(单击)鼠标时,会出现文本选择手柄,并且当单击文本选择手柄本身,然后出现 "paste" 菜单选项(当剪贴板中有文本时)。这就是我要阻止的。
据我从源代码中看到的,ActionPopupWindow
是随 PASTE/REPLACE 选项一起弹出的内容。 ActionPopupWindow 是私有抽象 class HandleView 中的受保护变量 (mActionPopupWindow) public class android.widget.Editor...
如果不禁用剪贴板服务或编辑 Android 源代码,有什么方法可以防止它显示吗?我尝试为 android:textSelectHandleWindowStyle
定义一个新样式,并将 android:visibility
设置为 gone
,但它不起作用(应用程序冻结了一段时间,否则它会显示)。
您可以使用此代码:
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;
}
});
}
从 onCreateActionMode
返回 false 将禁用 API 级别大于 11 的剪切、复制、粘贴选项。
或者直接使用
yourEditText.setLongClickable(false);
或 XML
android:longClickable="false"
更新
实际上用户想要禁用文本选择句柄本身
1.创建形状 (handle.xml)
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<size
android:height="0dp"
android:width="0dp" />
</shape>
2。在你的 EditText
android:textSelectHandle="@drawable/handle"
解决方法:在EditText
.
中覆盖isSuggestionsEnabled
和canPaste
对于快速解决方案,复制下面的 class - 此 class 覆盖 EditText
class,并相应地阻止所有事件。
有关详细信息,请继续阅读。
解决方案在于防止 PASTE/REPLACE 菜单出现在(未记录的)android.widget.Editor
class 的 show()
方法中。在菜单出现之前,检查 if (!canPaste && !canSuggest) return;
。用作设置这些变量的基础的两种方法都在 EditText
class:
isSuggestionsEnabled()
is public,因此可能会被覆盖。
canPaste()
is not, and thus must be hidden by introducing a function of the same name在派生class.
因此将这些更新合并到一个 class 中,该 class 也有 setCustomSelectionActionModeCallback, and the disabled long-click, here is the full class to prevent all editing (but still display the text selection handler) 用于控制光标:
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) {}
}
}
我已经在 Android v4.4.2 和 v4.4.3 中对此进行了测试。
在根本没有出现蓝色视图(插入控制器)时找到了另一个解决方案。我使用反射来设置编辑器 class 的目标布尔字段。查看 android.widget.Editor 和 android.widget.TextView 了解更多详情。
将以下代码添加到您的自定义 EditText 中(以及本主题中之前的所有代码):
@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
}
}
此外,也许您可以找到比 onTouch() 更好的地方来调用目标方法。
在 Android 5.1
上测试
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.
我找不到隐藏菜单弹出窗口的方法,但如果用户点击菜单,您可以禁止粘贴
创建自定义 EditText
并为 android.R.id.paste
和 android.R.id.pasteAsPlainText
菜单 ID 覆盖 onTextContextMenuItem
方法和 return false。
@Override
public boolean onTextContextMenuItem(int id) {
switch (id){
case android.R.id.paste:
case android.R.id.pasteAsPlainText:
return false;
}
return super.onTextContextMenuItem(id);
}
None 以上解决方案对我有用。我已经设法完成了我的解决方案(之后解释),它禁止在 EditText 上粘贴任何内容,同时保持所有其他操作有效。
主要是,您必须在 EditText 的实现中覆盖此方法:
@Override
public boolean onTextContextMenuItem (int id) {
if (id == android.R.id.paste) return false;
return super.onTextContextMenuItem(id);
}
因此调查 EditText 代码,在所有检查之后,粘贴(以及 EditText 上的所有 ContextMenu
操作)发生在名为 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;
}
如果您注意到,粘贴只会在 id == ID_PASTE
时发生,因此,再次查看 EditText 代码:
static final int ID_PASTE = android.R.id.paste;
这是禁用 "paste" 弹出窗口的技巧。您必须覆盖 EditText
方法:
@Override
public int getSelectionStart() {
for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
if (element.getMethodName().equals("canPaste")) {
return -1;
}
}
return super.getSelectionStart();
}
与公认的答案不同,此解决方案也适用于 Android 的较新版本。
如果您需要删除 PASTE 建议,请在长按之前清空剪贴板。
//class
ClipboardManager clipboard;
//oncreate
clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("","");
clipboard.setPrimaryClip(clip);
我找到了一个简单而可靠的方法。这个想法是消耗掉触摸事件,以防止触摸事件达到下划线默认代码。
- 禁用 copy/paste 弹出窗口。
- 禁用文本选择处理程序。
- 仍然在文本末尾显示光标。
- 仍在显示键盘。
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);
}
请注意,闪烁的光标仍显示在文本末尾。只是截图无法截取。
只需覆盖一种方法:
@Override
protected MovementMethod getDefaultMovementMethod() {
// we don't need arrow key, return null will also disable the copy/paste/cut pop-up menu.
return null;
}
您可以通过执行以下操作完全删除 menuItem:
Java:
ActionMode.Callback callback = new ActionMode.Callback() {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
if (menu != null) {
menu.removeItem(android.R.id.paste);
}
return true;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
}
};
mEditText.setCustomInsertionActionModeCallback(callback);
mEditText.setCustomSelectionActionModeCallback(callback);
科特林:
val callback = object : ActionMode.Callback {
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
return false
}
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
return true
}
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
menu?.removeItem(android.R.id.paste)
return true
}
override fun onDestroyActionMode(mode: ActionMode?) {}
}
然后在 EditText 中使用站点:
fun preventPaste() {
customInsertionActionModeCallback = callback
customSelectionActionModeCallback = callback
}
我找到了一个简单的 solution.Hope 它会对某人有所帮助,扩展 Edittetxt class 和下面的 ovverride 方法。
同样,如果你想通过比较 menu.getItem(i).getTitle()
来禁用其他选项,你可以这样做。
private class ActionModeCallbackInterceptor implements ActionMode.Callback
{
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
return true;
}
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
for(int i =0;i<menu.size();i++){
if(menu.getItem(i).getTitle().toString().equals("Clipboard")
|| menu.getItem(i).getTitle().toString().equals("Paste")) {
menu.getItem(i).setVisible(false);
}
}
return false;
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
public void onDestroyActionMode(ActionMode mode) {}
}
通过下面提到的所有 3 个更改修复了它
fun TextView.disableCopyPaste() {
isLongClickable = false. // change 1 , disable Long click
setTextIsSelectable(false). // change 2 , disable text selection click
//change 3 , return false from all actionmode
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?) {}
}
}
我刚刚在 Android 11 中使用了上面的一些解决方案并且它工作正常,您可以使用下面的要点。
https://gist.github.com/harshmittal2810/26429eb426dd1b31750cb33b47f449a6
我的目标是 EditText
没有花哨的功能,只有文本 Selection 处理程序可以更轻松地移动光标 -- 因此没有上下文菜单或 pop-ups .
根据 this solution.
,我通过使用 ActionMode Callback 事件禁用了文本编辑功能操作栏(copy/Paste 等)的外观中间的中间文本 Select 句柄(见下图)在字段中存在文本并且在文本中发生单击时仍然出现。伟大的!我想保持这种行为。我不想要的是 "PASTE" 菜单在单击文本 Select 句柄本身时出现。
我还通过在样式 XML 中设置 android:longClickable="false"
禁用了 EditText 的 long-click 输入。禁用长按可防止在单击并按住鼠标(即长按)时显示 "Paste/Replace" 菜单,但是当在文本中单击(单击)鼠标时,会出现文本选择手柄,并且当单击文本选择手柄本身,然后出现 "paste" 菜单选项(当剪贴板中有文本时)。这就是我要阻止的。
据我从源代码中看到的,ActionPopupWindow
是随 PASTE/REPLACE 选项一起弹出的内容。 ActionPopupWindow 是私有抽象 class HandleView 中的受保护变量 (mActionPopupWindow) public class android.widget.Editor...
如果不禁用剪贴板服务或编辑 Android 源代码,有什么方法可以防止它显示吗?我尝试为 android:textSelectHandleWindowStyle
定义一个新样式,并将 android:visibility
设置为 gone
,但它不起作用(应用程序冻结了一段时间,否则它会显示)。
您可以使用此代码:
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;
}
});
}
从 onCreateActionMode
返回 false 将禁用 API 级别大于 11 的剪切、复制、粘贴选项。
或者直接使用
yourEditText.setLongClickable(false);
或 XML
android:longClickable="false"
更新
实际上用户想要禁用文本选择句柄本身
1.创建形状 (handle.xml)
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<size
android:height="0dp"
android:width="0dp" />
</shape>
2。在你的 EditText
android:textSelectHandle="@drawable/handle"
解决方法:在EditText
.
isSuggestionsEnabled
和canPaste
对于快速解决方案,复制下面的 class - 此 class 覆盖 EditText
class,并相应地阻止所有事件。
有关详细信息,请继续阅读。
解决方案在于防止 PASTE/REPLACE 菜单出现在(未记录的)android.widget.Editor
class 的 show()
方法中。在菜单出现之前,检查 if (!canPaste && !canSuggest) return;
。用作设置这些变量的基础的两种方法都在 EditText
class:
isSuggestionsEnabled()
is public,因此可能会被覆盖。canPaste()
is not, and thus must be hidden by introducing a function of the same name在派生class.
因此将这些更新合并到一个 class 中,该 class 也有 setCustomSelectionActionModeCallback, and the disabled long-click, here is the full class to prevent all editing (but still display the text selection handler) 用于控制光标:
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) {}
}
}
我已经在 Android v4.4.2 和 v4.4.3 中对此进行了测试。
在根本没有出现蓝色视图(插入控制器)时找到了另一个解决方案。我使用反射来设置编辑器 class 的目标布尔字段。查看 android.widget.Editor 和 android.widget.TextView 了解更多详情。
将以下代码添加到您的自定义 EditText 中(以及本主题中之前的所有代码):
@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
}
}
此外,也许您可以找到比 onTouch() 更好的地方来调用目标方法。
在 Android 5.1
上测试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.
我找不到隐藏菜单弹出窗口的方法,但如果用户点击菜单,您可以禁止粘贴
创建自定义 EditText
并为 android.R.id.paste
和 android.R.id.pasteAsPlainText
菜单 ID 覆盖 onTextContextMenuItem
方法和 return false。
@Override
public boolean onTextContextMenuItem(int id) {
switch (id){
case android.R.id.paste:
case android.R.id.pasteAsPlainText:
return false;
}
return super.onTextContextMenuItem(id);
}
None 以上解决方案对我有用。我已经设法完成了我的解决方案(之后解释),它禁止在 EditText 上粘贴任何内容,同时保持所有其他操作有效。
主要是,您必须在 EditText 的实现中覆盖此方法:
@Override
public boolean onTextContextMenuItem (int id) {
if (id == android.R.id.paste) return false;
return super.onTextContextMenuItem(id);
}
因此调查 EditText 代码,在所有检查之后,粘贴(以及 EditText 上的所有 ContextMenu
操作)发生在名为 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;
}
如果您注意到,粘贴只会在 id == ID_PASTE
时发生,因此,再次查看 EditText 代码:
static final int ID_PASTE = android.R.id.paste;
这是禁用 "paste" 弹出窗口的技巧。您必须覆盖 EditText
方法:
@Override
public int getSelectionStart() {
for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
if (element.getMethodName().equals("canPaste")) {
return -1;
}
}
return super.getSelectionStart();
}
与公认的答案不同,此解决方案也适用于 Android 的较新版本。
如果您需要删除 PASTE 建议,请在长按之前清空剪贴板。
//class
ClipboardManager clipboard;
//oncreate
clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("","");
clipboard.setPrimaryClip(clip);
我找到了一个简单而可靠的方法。这个想法是消耗掉触摸事件,以防止触摸事件达到下划线默认代码。
- 禁用 copy/paste 弹出窗口。
- 禁用文本选择处理程序。
- 仍然在文本末尾显示光标。
- 仍在显示键盘。
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);
}
请注意,闪烁的光标仍显示在文本末尾。只是截图无法截取。
只需覆盖一种方法:
@Override
protected MovementMethod getDefaultMovementMethod() {
// we don't need arrow key, return null will also disable the copy/paste/cut pop-up menu.
return null;
}
您可以通过执行以下操作完全删除 menuItem:
Java:
ActionMode.Callback callback = new ActionMode.Callback() {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
if (menu != null) {
menu.removeItem(android.R.id.paste);
}
return true;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
}
};
mEditText.setCustomInsertionActionModeCallback(callback);
mEditText.setCustomSelectionActionModeCallback(callback);
科特林:
val callback = object : ActionMode.Callback {
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
return false
}
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
return true
}
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
menu?.removeItem(android.R.id.paste)
return true
}
override fun onDestroyActionMode(mode: ActionMode?) {}
}
然后在 EditText 中使用站点:
fun preventPaste() {
customInsertionActionModeCallback = callback
customSelectionActionModeCallback = callback
}
我找到了一个简单的 solution.Hope 它会对某人有所帮助,扩展 Edittetxt class 和下面的 ovverride 方法。
同样,如果你想通过比较 menu.getItem(i).getTitle()
来禁用其他选项,你可以这样做。
private class ActionModeCallbackInterceptor implements ActionMode.Callback
{
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
return true;
}
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
for(int i =0;i<menu.size();i++){
if(menu.getItem(i).getTitle().toString().equals("Clipboard")
|| menu.getItem(i).getTitle().toString().equals("Paste")) {
menu.getItem(i).setVisible(false);
}
}
return false;
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
public void onDestroyActionMode(ActionMode mode) {}
}
通过下面提到的所有 3 个更改修复了它
fun TextView.disableCopyPaste() {
isLongClickable = false. // change 1 , disable Long click
setTextIsSelectable(false). // change 2 , disable text selection click
//change 3 , return false from all actionmode
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?) {}
}
}
我刚刚在 Android 11 中使用了上面的一些解决方案并且它工作正常,您可以使用下面的要点。
https://gist.github.com/harshmittal2810/26429eb426dd1b31750cb33b47f449a6