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

发布时间 2023-10-16 21:19:46作者: 小满独家

内容来自 DOC https://q.houxu6.top/?s=如何以编程方式关闭/隐藏Android软键盘?

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

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


为了澄清这个疯狂的问题,我想首先代表所有 Android 用户就谷歌对软键盘的荒谬处理道歉。为什么对于同一个简单问题有如此多不同的答案,每个答案都不同呢?这是因为这个 API(就像 Android 中的许多其他 API)设计得非常糟糕。我找不到任何礼貌的方式来表达它。

我想要隐藏键盘。我希望提供给 Android 以下语句:Keyboard.hide()。结束。非常感谢。但是 Android 有一个问题。你必须使用 InputMethodManager 来隐藏键盘。好的,可以接受,这是 Android 的 API 来控制键盘。但是!你必须有一个 Context 才能访问 IMM。现在我们有问题了。我可能希望从一个没有使用或需要任何 Context 的静态或实用类中隐藏键盘,或者更糟糕的是,IMM 要求你指定要隐藏键盘的 View(甚至更糟糕的是,指定要隐藏键盘的 Window)。

这使得隐藏键盘变得非常具有挑战性。亲爱的谷歌:当我在寻找蛋糕的食谱时,地球上没有 RecipeProvider 会拒绝提供食谱,除非我先回答蛋糕将由谁享用以及在哪里享用!

这个悲伤的故事以丑陋的事实结束:要隐藏 Android 键盘,你必须提供两种形式的标识:一个 Context 和一个 ViewWindow

我创建了一个静态实用方法,可以在提供 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 调用时才有效!上述方法调用目标 ActivitygetCurrentFocus 来获取正确的窗口令牌。

但是假设你想要从 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 会自动将初始焦点分配给你的 Activity 中的第一个 EditText 或可聚焦控件。自然地,由于焦点事件,输入法(通常是软键盘)会响应并显示自己。在 AndroidManifest.xml 中设置的 windowSoftInputMode 属性为 stateAlwaysHidden,指示键盘忽略自动分配的初始焦点。

<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();