我正在为传统蒙古人制作一个垂直EditText
。我通过在旋转的EditText
内嵌入略微修改的ViewGroup
来成功实现它。我需要创建一个完全自定义的上下文菜单,因为系统不支持垂直文本,并且在ViewGroup
旋转时也不会旋转。所以我想完全禁用系统上下文菜单。
请注意,这与仅仅尝试禁用复制/粘贴/等的这些问题不同:
虽然我没有在模拟器中显示上下文菜单,但我将其显示在我的Android 5.0.2小米手机中。
我试过了:
setCustomSelectionActionModeCallback
"solution" setLongClickable(false);
"solution" onTouchEvent
"solution" 我对hacks持开放态度,但我需要它能够在各种设备上持续工作。 Mark Murphy(一个Commons Guy)wrote一段时间回复了另一个尝试做类似事情的用户:
我怀疑即使你想出答案,它也行不通 跨设备。设备制造商倾向于推出他们的产品 拥有"上下文菜单"对于EditText,击败开发者'尝试添加 项目进入该上下文菜单。我的猜测是试图阻止它 上下文菜单会有类似的结果。
我运气不好吗?
我现在唯一能想到的就是从头开始重写TextView
和EditText
(好吧,修改Android源代码)。我知道其他人做了类似的事,但他的代码不是开源的。在我采取这一重大步骤之前,我想尝试在Stack Overflow上寻求更简单的解决方案。
更新:我过去两天一直在尝试修改TextView
源代码,看起来像是一个6个月的项目。这是一大堆相互关联的课程。我需要另一种解决方案,但我没有想法。
MVCE
这是我能想到的最简单的方法来重现问题。我的自定义EditText
没有必要。通过替换默认项目Hello World' s EditText
,布局有一个TextView
。我将min API更改为11以避免处理已弃用的方法。
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) { }
});
}
}
模拟器(运行API 24)中的上下文菜单仍然显示我单击光标手柄(但不是长按或双击)。这是一张图片:
在运行Android 5.0的小米MIUI手机上,我得到了所有情况下的上下文菜单(光标处理点击,长按,双击)。
Aritra Roy的解决方案是在模拟器中,在他测试的其他设备上以及我的设备上工作。我接受了他的答案,因为它解决了我原来的问题。唯一的负面影响是文本选择也被禁用。
答案 0 :(得分:21)
您需要做三件事。
第1步
您可以通过从这些方法返回false来禁用上下文菜单,
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;
}
});
第2步
还需要禁用EditText中的长按。
mEditText.setLongClickable(false);
或执行此操作,XML中的android:longClickable="false"
。
第3步
现在,您需要防止在单击手柄时显示菜单。解决方案很简单,
1)扩展EditText
类,
2)覆盖isSuggestionsEnabled()
并返回false
,
3)创建canPaste()
方法并返回false
。这是方法隐藏。
快速解决方案
如果您不想手动完成所有这些操作。这是一个自定义的EditText类,您可以使用它来快速完成此操作。但是我仍然建议你一次完成这些步骤,以了解事情是如何运作的。
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) {
}
}
}
答案 1 :(得分:3)
我已为EditText
制作了此代码,并且它适用于此类问题。
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();
}
答案 2 :(得分:2)
答案 3 :(得分:1)
mEditText.setLongClickable(false);
这是禁用编辑文本的最简单方法。
答案 4 :(得分:1)
这是一个难题。 我花了很多小时在我的 Android Studio 3.4.2 中进行研究和测试。
我建议3个步骤:
a)原始问题中的setCustomSelectionActionModeCallback "solution" 但是,当您单击红色下拉菜单时,它始终显示选择手柄(光标下方的红色下拉菜单)和“剪贴板+全选”弹出窗口。
b)为选择的手柄创建一个空白图像。我在ic_empty.xml
下创建了一个名为res/drawable
的文件。
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
</shape>
c)我已经在style.xml
中为所有EditTexts
创建了一种样式。
主要主题下
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
...
<item name="android:editTextStyle">@style/TStyle</item>
....
</style>
因此,您可以定义样式,为lef,中间和右选择手柄关联一个空图像:
<style name="TStyle" parent="@android:style/Widget.EditText" >
<item name="android:textSelectHandle">@drawable/ic_empty</item>
<item name="android:textSelectHandleLeft">@drawable/ic_empty</item>
<item name="android:textSelectHandleRight">@drawable/ic_empty</item>
</style>
如果目标来自API 23
,则可以使用setTextAppearance
在EditText
内的文本中附加样式。但是,以上解决方案始终有效
唯一剩下的问题是我可以摆脱双击的影响。它在文本中选择一个带有粉红色背景的单词。但是,它相对无害,但是很尴尬,因为它不需要用户交互。
可以将高亮颜色设置为透明的方法。
EditT.setHighlightColor(Color.TRANSPARENT) // EditT is a EditText
答案 5 :(得分:0)
这是阻止复制粘贴菜单以任何方式,形状或形式出现的方式。这个错误真的让我发疯,就像任何三星的bug一样,你知道它的代码,但你也知道他们很快就会解决它。无论如何,这里有奇妙的墙......
检查Android.Build.Model.toLowerCase()。startsWith(&#39; sm-g930&#39;)。不匹配整个字符串,最后一个字母是次要版本标识符。我将这个布尔值存储在了稍后出现的shouldBlockCopyPaste变量中。
如果匹配,则要阻止复制粘贴菜单显示。这就是你的实际行动方式!!!
覆盖这两个函数,你会注意到我的shouldBlockCopyPaste布尔值,这是其他设备不被阻止的。
function html2json() {
var otArr = [];
var tblHeaders = Array.from($('table thead tr')
.children())
.map(header => $(header).text());
var tbl2 = $('table tbody tr').each(function(e) {
const values = Array.from($(this).children());
const row = {};
for (let i = 0; i < tblHeaders.length; i++){
row[tblHeaders[i]] = $(values[i]).text();
}
otArr.push({
[e+1]: row
})
})
json = JSON.stringify(otArr);
return json;
}
答案 6 :(得分:0)
我尝试了上述所有答案,但没有得到完整的解决方案。 如果您只想禁用PASTE选项,则可以尝试以下操作:
override fun getSelectionStart(): Int {
for (element in Thread.currentThread().stackTrace) {
if (element.methodName == "canPaste") {
return -1
}
}
return super.getSelectionStart()
}
这只是一个hack,但是我没有发现更好的东西。
如果您想完全禁用菜单和光标,可以尝试使用以下类而不是EditText:
class MaskedCodeEditTextView : EditText {
constructor(context: Context) : super(context) {
init()
blockContextMenu()
}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
init()
blockContextMenu()
}
constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(
context,
attrs,
defStyle
) {
init()
blockContextMenu()
}
override fun getSelectionStart(): Int {
for (element in Thread.currentThread().stackTrace) {
if (element.methodName == "canPaste") {
return -1
}
}
return super.getSelectionStart()
}
private fun setInsertionDisabled() {
try {
val editorField = TextView::class.java.getDeclaredField("mEditor")
editorField.isAccessible = true
val editorObject = editorField[this]
val editorClass = Class.forName("android.widget.Editor")
val mInsertionControllerEnabledField =
editorClass.getDeclaredField("mInsertionControllerEnabled")
mInsertionControllerEnabledField.isAccessible = true
mInsertionControllerEnabledField[editorObject] = false
} catch (ignored: Exception) {
// ignore exception here
}
}
private fun blockContextMenu() {
this.customSelectionActionModeCallback = ActionModeCallbackInterceptor()
this.isLongClickable = false
setOnClickListener { v: View? ->
v?.let {
if(!it.isFocused) {
requestFocus()
} else {
clearFocus()
requestFocus()
}
}
}
}
override fun isSuggestionsEnabled(): Boolean {
return false
}
private fun init() {
this.customSelectionActionModeCallback = ActionModeCallbackInterceptor()
this.isLongClickable = false
}
override fun onTouchEvent(event: MotionEvent): Boolean {
if (event.action == MotionEvent.ACTION_DOWN) {
setInsertionDisabled()
}
return super.onTouchEvent(event)
}
private inner class ActionModeCallbackInterceptor : 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) {}
}
}
答案 7 :(得分:-1)
试试这个
mEditText.setClickable(false);
mEditText.setEnabled(false);
<强>更新强>
通过扩展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) {}
}
}