如何以编程方式关闭/隐藏 Android 软键盘?

新手上路,请多包涵

我的布局中有一个 EditText 和一个 Button

在编辑字段中写入并单击 Button 后,我想在键盘外触摸时隐藏虚拟键盘。我假设这是一段简单的代码,但我在哪里可以找到它的示例?

原文由 Vidar Vestnes 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.1k
2 个回答

为了帮助澄清这种疯狂,我想首先代表所有安卓用户为谷歌对软键盘的荒谬处理表示歉意。对于同一个简单的问题,有这么多答案,每一个都不同,原因是这个 API 和 Android 中的许多其他 API 一样,设计得很糟糕。我想不出有礼貌的说法。

我想隐藏键盘。我希望为 Android 提供以下声明: Keyboard.hide() 。结束。非常感谢。但是安卓有问题。您必须使用 InputMethodManager 来隐藏键盘。好的,好的,这是 Android 的键盘 API。但!您需要拥有 Context 才能访问 IMM。现在我们有一个问题。我可能想从一个静态或实用程序类中隐藏键盘,这些类没有使用或不需要任何 Context 。或者更糟糕的是,IMM 要求您指定要隐藏键盘的 View (或者更糟糕的是 Window )。

这就是隐藏键盘如此具有挑战性的原因。亲爱的谷歌:当我查找蛋糕的食谱时,地球上没有 RecipeProvider 会拒绝向我提供食谱,除非我先回答谁会吃蛋糕以及在哪里吃蛋糕会被吃掉!!

这个悲伤的故事以丑陋的事实结束:要隐藏 Android 键盘,您将需要提供 2 种形式的标识: ContextViewWindow .

我创建了一个静态实用程序方法,只要您从 Activity 调用它,它就可以非常可靠地完成这项工作。

 public static void hideKeyboard(Activity activity) {
    InputMethodManager imm = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
    //Find the currently focused view, so we can grab the correct window token from it.
    View view = activity.getCurrentFocus();
    //If no view currently has focus, create a new one, just so we can grab a window token from it
    if (view == null) {
        view = new View(activity);
    }
    imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}

请注意,此实用程序方法仅在从 Activity 调用时才有效!上述方法调用目标 getCurrentFocusActivity 来获取正确的窗口令牌。

但是假设您想隐藏 EditText 托管在 DialogFragment 中的键盘?您不能为此使用上述方法:

 hideKeyboard(getActivity()); //won't work

这不起作用,因为您将传递对 Fragment 的主机 Activity 的引用,当显示 Fragment 时,它将没有集中控制!哇!因此,为了将键盘从碎片中隐藏起来,我采用了更底层、更常见、更丑陋的方法:

 public static void hideKeyboardFrom(Context context, View view) {
    InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}

以下是从浪费更多时间追逐此解决方案中收集的一些附加信息:

关于windowSoftInputMode

还有一个争论点需要注意。默认情况下,Android 会自动将初始焦点分配给第一个 EditText 或您的 Activity 中的可聚焦控件。很自然地,InputMethod(通常是软键盘)将通过显示自己来响应焦点事件。 — 中的 windowSoftInputMode 属性设置为 stateAlwaysHidden AndroidManifest.xml ,指示键盘忽略此自动分配的初始焦点。

 <activity
    android:name=".MyActivity"
    android:windowSoftInputMode="stateAlwaysHidden"/>

几乎令人难以置信的是,当您触摸控件时,它似乎无法阻止键盘打开(除非将 focusable="false" 和/或 focusableInTouchMode="false" 分配给控件)。显然,windowSoftInputMode 设置仅适用于自动焦点事件,不适用于由触摸事件触发的焦点事件。

因此, stateAlwaysHidden 的名字确实很糟糕。或许应该改为 ignoreInitialFocus


更新:获取窗口令牌的更多方法

如果没有焦点视图(例如,如果您只是更改片段可能会发生),则有其他视图将提供有用的窗口标记。

这些是上述代码的替代品 if (view == null) view = new View(activity); 这些并不明确涉及您的活动。

在片段类中:

 view = getView().getRootView().getWindowToken();

给定一个片段 fragment 作为参数:

 view = fragment.getView().getRootView().getWindowToken();

从您的内容正文开始:

 view = findViewById(android.R.id.content).getRootView().getWindowToken();


更新 2:如果您从后台打开应用程序,请清除焦点以避免再次显示键盘

将此行添加到方法的末尾:

view.clearFocus();

原文由 rmirabelle 发布,翻译遵循 CC BY-SA 4.0 许可协议

您可以使用下面的扩展来隐藏和显示软键盘

fun Fragment.showKeyboard(view: View) {
    view.isFocusableInTouchMode = true
    view.requestFocus()
    val imm = view.context?.getSystemService(Context.INPUT_METHOD_SERVICE)
        as InputMethodManager
    imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT) }

fun Fragment.hideKeyboard(view: View) {
    view.clearFocus()
    val imm = view.context?.getSystemService(Context.INPUT_METHOD_SERVICE)
       as InputMethodManager
    imm.hideSoftInputFromWindow(view.windowToken, 0) }

要呼叫分机,您只需在片段中遵循以下步骤

showKeyboard(Your edittext ID)

hideKeboard(Your edittext ID)

原文由 Morteza Allahyari 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题