如何在保留复制/粘贴功能的前提下禁用EditText中的软键盘?

34

你好,我正在制作一个自定义拨号器,因此我创建了自己的输入面板。

问题是如何禁用EditText,但仍允许剪切/复制/粘贴?原始拨号器可以做到这一点。

我尝试过使用android:focusable="false",但它会禁用剪切/复制(仍然可以粘贴)。

我还尝试通过编程来禁用inputType,但这会禁用所有三个命令:

myEditText.setInputType(InputType.TYPE_NULL); //Can't cut/copy/paste

禁用它在清单中也不起作用:
android:configChanges="orientation|keyboardHidden" //Keyboard still popped up

任何解决方案?谢谢。
7个回答

58

经过数小时的研究,我终于找到了适用于所有API版本的解决方案。希望这可以节省某人的时间。

如果您正在开发API >= 11的应用程序,则解决方案很简单,只需要:

1)在EditText的xml文件中添加下面两个属性

android:inputType="none"
android:textIsSelectable="true"

或者

2)编程实现以下操作

myEditText.setInputType(InputType.TYPE_NULL);
myEditText.setTextIsSelectable(true);

完成了。

如果您想支持 API < 11,我发现没有办法禁止键盘弹出,如果您想选择文本进行复制粘贴操作。将 focusable 设为 false 可以禁用键盘,但这并没有帮助,因为它也禁用了选择文本的能力。在 stackoverflow 上找到的其他解决方案要么不起作用,要么同时禁用了文本选择。

一种丑陋的解决方法是这样的...

首先,在 EditText 的 xml 文件中添加此属性

android:editable="false"

虽然这种方法已经被弃用,但在API版本<11中,它仍然是使EditText不可编辑的必要方法。

接下来,我们需要在键盘出现时立即隐藏它,以便我们可以继续选择文本而不会被键盘挡住。

使用以下代码来检测键盘是否显示(解决方案来源于https://dev59.com/WHI95IYBdhLWcg3wyRM0#9108219),并立即将其隐藏。

if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB)
{
    final View activityRootView = findViewById(R.id.activityRoot);
    activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    @Override
        public void onGlobalLayout() {
            Rect r = new Rect();
            //r will be populated with the coordinates of your view that area still visible.
            activityRootView.getWindowVisibleDisplayFrame(r);

            int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
            if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...

            //Hide the keyboard instantly!
            if (getCurrentFocus() != null) 
            {
                InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
            }
            }
         }
        });
}

对于我的情况,它起作用了。虽然你可以看到键盘在一瞬间弹出(这是丑陋的部分),但我现在写的时候想不出其他方法来使它工作。如果你有更好的解决方案,请留言!

如果这节省了某人的时间,请让我知道 :)


谢谢,这比我之前用的更好,但至少在KitKat中还没有默认粘贴选项?我只看到长按时的全选和复制。 - Anonsage
3
很好,但是myEditText.setInputType(InputType.TYPE_NULL);会让EditText变成单行,即使结合了InputType.TYPE_NULL | InputType.TYPE_TEXT_FLAG_MULTI_LINE - Quark
我只需要添加 android:textIsSelectable="true" 就可以了。是否还需要加上 myEditText.setInputType(InputType.TYPE_NULL); - Suragch
@Suragch 如果你需要禁用软键盘(不允许输入),那么是的。 - Bruce
在我的测试中,软键盘在没有设置InputType的情况下被禁用了。你使用的是哪个Android API版本? - Suragch
显示剩余2条评论

37

要禁用软键盘的显示,同时保留复制/粘贴和光标功能,请在您的活动中添加以下行:

```java getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); ```
getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
    WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);

1
这对我非常有效,保留了光标和上下文菜单,而且它适用于Android O(v.26)。我的要求是v.19到v.26。我将其放在包含EditText控件的活动的onCreate方法中。 - Gail

7

由于当前的最佳答案使用了已过时的方法,并且没有适用于我的粘贴方法,因此这里提供另一种不使用旧方法的方法。但是,它确实尝试通过反射使用隐藏的方法,并提供备用方案。=)

我对EditText进行了子类化,创建了一个名为KeyboardlessEditText的新小部件,仍然保留所有酷炫的编辑功能,而无需显示键盘。只需放入文件即可。

完整代码有点长,不便在此处展示,但只要 GitHub 没有崩溃,那么这个链接就有效:https://github.com/danialgoodwin/android-widget-keyboardless-edittext/blob/master/KeyboardlessEditText2.java


这太棒了,几乎完美!只有一个问题:在某种情况下仍然会显示键盘,即如果将应用程序发送到后台,然后返回,则会显示键盘:( 有什么解决方法吗?我已经尝试了接受的答案(不起作用),还尝试了设置父级可聚焦但没有帮助……仍然没有找到既没有键盘又可以复制/粘贴的解决方案。 - daneejela
在将应用程序发送到后台(和打开)的哪些方法中,键盘会显示?我无法在尝试了六种不同的关闭/打开组合(使用Nexus 4 API 21)中重新创建此操作。 - Anonsage

7

要禁用EditTextTextView的系统键盘自动弹出,请按照以下步骤操作:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    editTextView.setShowSoftInputOnFocus(false);
} else {
    editTextView.setTextIsSelectable(true);
    //N.B. Accepting the case when non editable text will be selectable
}

4

我之前遇到了同样的问题,但后来我又想允许在双击后输入... 在数小时的搜索后,我找到了可行的解决方案(至少对我而言)。在您的onCreate方法中使用以下内容:

editText.setCursorVisible(false);
editText.setTextIsSelectable(true);
editText.setShowSoftInputOnFocus(false);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);  // This just hide keyboard when activity starts

这些代码一定能解决问题... 如果想要撤销,可以使用以下代码:

editText.setCursorVisible(true);
editText.setShowSoftInputOnFocus(true);

重新显示键盘的方法是:
private void showSoftKeyboard(View view) {
    InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
    view.requestFocus();
    inputMethodManager.showSoftInput(view, 0);
}

为了下次方便复制/粘贴,请使用以下三行代码:

editText.setCursorVisible(false);
editText.setTextIsSelectable(true);
editText.setShowSoftInputOnFocus(false);

想要进一步隐藏键盘,请使用以下方法:

private void hideSoftKeyboard() {
    if(getCurrentFocus() != null) {
        InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
        inputMethodManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
    }
}

这段代码适用于API版本>=21


这可能会对某些人有帮助。我使用按钮创建了一个键盘布局,并将其作为片段加载。因此,我想禁用软键盘而不禁用(闪烁的)光标。使用editText.setShowSoftInputOnFocus(false);就可以完成任务。用户仍然可以单击以将光标放置在需要进行编辑的位置。现在,我需要编写代码来删除光标,以便进行编辑。Android是如此有趣。我喜欢它。 - user9329083

3

试一试

 EditText et = ... // your EditText

et.setKeyListener(null) //makes the EditText non-editable so, it acts like a TextView.

无需子类化。与使EditText不可聚焦的方法相比,主要区别在于EditText仍然具有自己的光标——您可以选择文本等。它所做的只是抑制IME弹出自己的软键盘。


谢谢回复。但是那种方式会隐藏光标,因此无法剪切/复制/粘贴。 - hrsetyono

1

由于我的自定义内联“伪”输入框在焦点移动到编辑文本后仍可见,因此我有类似的需求。解决方法是使编辑文本在前一个自定义输入小部件完成其编辑生命周期之前隐藏软输入。

我受到@Bruce's answer的启发,并看到了一些相关的帖子,我会在最后附上它们。我找到的解决方案是:

fun setInputType(inputType: Int) {
        getEditText().setRawInputType(inputType)
        if (inputType == InputType.TYPE_NULL) {
            getEditText().setTextIsSelectable(true)
            getEditText().isCursorVisible = true
        }
    }

当从InputType.TYPE_NULL切换回InputType.TYPE_TEXT_FLAG_MULTI_LINE时,多行文本输入不受尊重,因此必须使用setRawInputType()。似乎有用户报告调用setInputType(InputType.TYPE_NULL)时出现问题。请参见: https://issuetracker.google.com/issues/36907992

其他有用的相关帖子:

如何通过XML在Android中使EditText不可编辑?

EditText不可编辑


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接