我在我的布局中有一个EditText
和一个Button
。
在编辑字段中写入内容并点击Button
后,我希望在触摸键盘外部时隐藏虚拟键盘。我认为这是一段简单的代码,但是我在哪里可以找到它的示例?
为了澄清这个疯狂的问题,我想首先代表所有 Android 用户就谷歌对软键盘的荒谬处理道歉。为什么对于同一个简单问题有如此多不同的答案,每个答案都不同呢?这是因为这个 API(就像 Android 中的许多其他 API)设计得非常糟糕。我找不到任何礼貌的方式来表达它。
我想要隐藏键盘。我希望提供给 Android 以下语句:Keyboard.hide()
。结束。非常感谢。但是 Android 有一个问题。你必须使用 InputMethodManager
来隐藏键盘。好的,可以接受,这是 Android 的 API 来控制键盘。但是!你必须有一个 Context
才能访问 IMM。现在我们有问题了。我可能希望从一个没有使用或需要任何 Context
的静态或实用类中隐藏键盘,或者更糟糕的是,IMM 要求你指定要隐藏键盘的 View
(甚至更糟糕的是,指定要隐藏键盘的 Window
)。
这使得隐藏键盘变得非常具有挑战性。亲爱的谷歌:当我在寻找蛋糕的食谱时,地球上没有 RecipeProvider
会拒绝提供食谱,除非我先回答蛋糕将由谁享用以及在哪里享用!
这个悲伤的故事以丑陋的事实结束:要隐藏 Android 键盘,你必须提供两种形式的标识:一个 Context
和一个 View
或 Window
。
我创建了一个静态实用方法,可以在提供 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
调用时才有效!上述方法调用目标 Activity
的 getCurrentFocus
来获取正确的窗口令牌。
但是假设你想要从 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();