CJB*_*JBS 18 android contextmenu android-widget android-edittext
我的目标是拥有一个EditText没有花哨功能,只有文本选择处理程序更容易移动光标 - 所以没有上下文菜单或弹出窗口.
根据此解决方案,我已通过使用ActionMode Callback事件禁用了文本编辑功能操作栏(复制/粘贴等)的外观.
当文本存在于字段中并且文本中出现单击时,仍然会出现中间中间文本选择句柄(请参见下图).大!我想保持这种行为.我不想要的是单击文本选择句柄本身时出现的"粘贴"菜单.

我还通过设置android:longClickable="false"样式XML 禁用了EditText的长按输入.禁用长按可防止单击鼠标(即长按)时出现"粘贴/替换"菜单,但是当在文本中单击鼠标(单触)时,会出现文本选择手柄,并且单击文本选择手柄本身,然后出现"粘贴"菜单选项(当剪贴板中有文本时).这就是我想要阻止的.
从我从源头看到的内容,ActionPopupWindow就是PASTE/REPLACE选项弹出的内容.ActionPopupWindow是公共类android.widget.Editor中私有抽象类HandleView中的受保护变量(mActionPopupWindow)...
如果没有禁用剪贴板服务或编辑Android源代码,有没有办法阻止它显示?我试图定义一个新的样式android:textSelectHandleWindowStyle,并设置android:visibility为gone,但它不起作用(应用程序冻结了一段时间,否则它会显示).
CJB*_*JBS 20
解决方案:覆盖isSuggestionsEnabled并canPaste进入EditText.
对于快速解决方案,请复制下面的类 - 此类将覆盖EditText该类,并相应地阻止所有事件.
对于细节,请继续阅读.
解决方案在于防止PASTE/REPLACE菜单出现在show()(未记录的)android.widget.Editor类的方法中.在菜单出现之前,进行检查if (!canPaste && !canSuggest) return;.用作设置这些变量的基础的两个方法都在EditText类中:
isSuggestionsEnabled()是公开的,因此可能被覆盖.canPaste()不是,因此必须通过在派生类中引入相同名称的函数来隐藏它.因此,将这些更新合并到也具有setCustomSelectionActionModeCallback的类中,并禁用长按,这里是完整的类,以防止所有编辑(但仍显示文本选择处理程序)来控制游标:
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) {}
}
}
Run Code Online (Sandbox Code Playgroud)
我在Android v4.4.2和v4.4.3中测试了这个.
Mur*_*ain 14
或者只是使用
yourEditText.setLongClickable(false);
Run Code Online (Sandbox Code Playgroud)
或者在XML中
android:longClickable="false"
Run Code Online (Sandbox Code Playgroud)
更新
实际上用户想要禁用文本选择句柄本身
1.创建一个形状(handle.xml)
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<size
android:height="0dp"
android:width="0dp" />
</shape>
Run Code Online (Sandbox Code Playgroud)
2.在EditText中
android:textSelectHandle="@drawable/handle"
Run Code Online (Sandbox Code Playgroud)
这是一个禁用"粘贴"弹出窗口的黑客.你必须覆盖EditText方法:
@Override
public int getSelectionStart() {
for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
if (element.getMethodName().equals("canPaste")) {
return -1;
}
}
return super.getSelectionStart();
}
Run Code Online (Sandbox Code Playgroud)
与已接受的答案不同,此解决方案也适用于较新版本的Android.
我找不到隐藏菜单弹出窗口的方法,但如果用户点击菜单,您可以禁用粘贴
创建一个自定义EditText并覆盖该onTextContextMenuItem方法并返回false for android.R.id.paste和android.R.id.pasteAsPlainTextmenu id.
@Override
public boolean onTextContextMenuItem(int id) {
switch (id){
case android.R.id.paste:
case android.R.id.pasteAsPlainText:
return false;
}
return super.onTextContextMenuItem(id);
}
Run Code Online (Sandbox Code Playgroud)
您可以通过执行以下操作完全删除 menuItem:
爪哇:
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);
Run Code Online (Sandbox Code Playgroud)
科特林:
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?) {}
}
Run Code Online (Sandbox Code Playgroud)
然后在 EditText 中使用站点:
fun preventPaste() {
customInsertionActionModeCallback = callback
customSelectionActionModeCallback = callback
}
Run Code Online (Sandbox Code Playgroud)
当蓝色视图(插入控制器)根本没有出现时找到另一个解决方案.我使用反射来设置Editor类的目标布尔字段.查看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
}
}
Run Code Online (Sandbox Code Playgroud)
此外,也许你可以找到比onTouch()更好的地方来调用目标方法.
在Android 5.1上测试过
| 归档时间: |
|
| 查看次数: |
26493 次 |
| 最近记录: |