如何以编程方式关闭/隐藏 Android 软键盘?
我的布局中有一个 EditText
和一个 Button
。
在编辑字段中写入并单击 Button
后,我想在触摸键盘外部时隐藏虚拟键盘。有人可以提供一个简单的例子来说明如何实现这一目标吗?
I have an EditText
and a Button
in my layout.
After writing in the edit field and clicking on the Button
, I want to hide the virtual keyboard when touching outside the keyboard. Can someone provide a simple example of how to achieve this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
您可以使用 InputMethodManager 强制 Android 隐藏虚拟键盘,调用
hideSoftInputFromWindow
,传入包含焦点视图的窗口的令牌。这将强制键盘在所有情况下都隐藏。在某些情况下,您需要传入
InputMethodManager.HIDE_IMPLICIT_ONLY
作为第二个参数,以确保仅在用户未显式强制键盘显示(通过按住菜单)时隐藏键盘。注意:如果您想在 Kotlin 中执行此操作,请使用:
context?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
Kotlin 语法
You can force Android to hide the virtual keyboard using the InputMethodManager, calling
hideSoftInputFromWindow
, passing in the token of the window containing your focused view.This will force the keyboard to be hidden in all situations. In some cases, you will want to pass in
InputMethodManager.HIDE_IMPLICIT_ONLY
as the second parameter to ensure you only hide the keyboard when the user didn't explicitly force it to appear (by holding down the menu).Note: If you want to do this in Kotlin, use:
context?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
Kotlin Syntax
为了澄清这种疯狂行为,我首先代表所有 Android 用户对 Google 对软键盘的彻底荒谬的处理表示歉意。对于同一个简单的问题,之所以有这么多不同的答案,是因为这个 API 和 Android 中的许多其他 API 一样,设计得很糟糕。我想不出有什么礼貌的方式来表达它。
我想隐藏键盘。我希望为 Android 提供以下语句:
Keyboard.hide()
。结束。非常感谢。但安卓有一个问题。您必须使用InputMethodManager
来隐藏键盘。好吧,好吧,这是 Android 的键盘 API。但!您需要拥有Context
才能访问 IMM。现在我们有一个问题。我可能想对没有任何Context
使用或不需要的静态或实用程序类隐藏键盘。或者更糟糕的是,IMM 要求您指定要隐藏键盘的View
(或者更糟糕的是,什么Window
)。这就是隐藏键盘如此具有挑战性的原因。亲爱的 Google:当我查找蛋糕的食谱时,地球上没有
RecipeProvider
会拒绝向我提供食谱,除非我首先回答蛋糕将被谁吃以及在哪里吃会被吃掉的!!这个悲伤的故事以丑陋的事实结束:要隐藏 Android 键盘,您将需要提供 2 种形式的标识:
Context
和View
或>窗口
。我创建了一个静态实用方法,只要您从
Activity
调用它,它就可以非常可靠地完成这项工作。请注意,此实用程序方法仅在从
Activity
调用时才有效!上述方法调用目标Activity
的getCurrentFocus
来获取正确的窗口令牌。但是假设您想对
DialogFragment
中托管的EditText
隐藏键盘?您不能使用上面的方法:这不起作用,因为您将传递对
Fragment
的主机Activity
的引用,而该主机没有显示Fragment
时获得焦点控制!哇!因此,为了隐藏片段中的键盘,我诉诸于较低级别、更常见且更丑陋的方法:下面是从浪费更多时间来追求此解决方案中收集到的一些附加信息:
关于 windowSoftInputMode
还有一点需要注意的争论。默认情况下,Android 会自动将初始焦点分配给
Activity
中的第一个EditText
或可聚焦控件。很自然地,InputMethod(通常是软键盘)将通过显示自身来响应焦点事件。当AndroidManifest.xml
中的windowSoftInputMode
属性设置为stateAlwaysHidden
时,指示键盘忽略此自动分配的初始焦点。几乎令人难以置信的是,当您触摸控件时,它似乎没有采取任何措施阻止键盘打开(除非分配了
focusable="false"
和/或focusableInTouchMode="false"
到控制器)。显然,windowSoftInputMode设置仅适用于自动焦点事件,不适用于触摸事件触发的焦点事件。因此,stateAlwaysHidden 的命名确实非常糟糕。也许应该将其称为“ignoreInitialFocus”。
更新:获取窗口令牌的更多方法
如果没有聚焦视图(例如,如果您刚刚更改了片段,则可能会发生),还有其他视图可以提供有用的窗口令牌。
这些是上述代码的替代方案
if (view == null) view = new View(activity);
这些代码并不明确引用您的 Activity。在片段类内部:
给定片段
fragment
作为参数:从内容正文开始:
更新 2:清除焦点以避免在从后台打开应用程序时再次显示键盘
将此行添加到方法的末尾:
view.clearFocus();
To help clarify this madness, I'd like to begin by apologizing on behalf of all Android users for Google's downright ridiculous treatment of the soft keyboard. The reason there are so many answers, each different, for the same simple question is that this API, like many others in Android, is horribly designed. I can think of no polite way to state it.
I want to hide the keyboard. I expect to provide Android with the following statement:
Keyboard.hide()
. The end. Thank you very much. But Android has a problem. You must use theInputMethodManager
to hide the keyboard. OK, fine, this is Android's API to the keyboard. BUT! You are required to have aContext
in order to get access to the IMM. Now we have a problem. I may want to hide the keyboard from a static or utility class that has no use or need for anyContext
. or And FAR worse, the IMM requires that you specify whatView
(or even worse, whatWindow
) you want to hide the keyboard FROM.This is what makes hiding the keyboard so challenging. Dear Google: When I'm looking up the recipe for a cake, there is no
RecipeProvider
on Earth that would refuse to provide me with the recipe unless I first answer WHO the cake will be eaten by AND where it will be eaten!!This sad story ends with the ugly truth: to hide the Android keyboard, you will be required to provide 2 forms of identification: a
Context
and either aView
or aWindow
.I have created a static utility method that can do the job VERY solidly, provided you call it from an
Activity
.Be aware that this utility method ONLY works when called from an
Activity
! The above method callsgetCurrentFocus
of the targetActivity
to fetch the proper window token.But suppose you want to hide the keyboard from an
EditText
hosted in aDialogFragment
? You can't use the method above for that:This won't work because you'll be passing a reference to the
Fragment
's hostActivity
, which will have no focused control while theFragment
is shown! Wow! So, for hiding the keyboard from fragments, I resort to the lower-level, more common, and uglier:Below is some additional information gleaned from more time wasted chasing this solution:
About windowSoftInputMode
There's yet another point of contention to be aware of. By default, Android will automatically assign initial focus to the first
EditText
or focusable control in yourActivity
. It naturally follows that the InputMethod (typically the soft keyboard) will respond to the focus event by showing itself. ThewindowSoftInputMode
attribute inAndroidManifest.xml
, when set tostateAlwaysHidden
, instructs the keyboard to ignore this automatically-assigned initial focus.Almost unbelievably, it appears to do nothing to prevent the keyboard from opening when you touch the control (unless
focusable="false"
and/orfocusableInTouchMode="false"
are assigned to the control). Apparently, the windowSoftInputMode setting applies only to automatic focus events, not to focus events triggered by touch events.Therefore,
stateAlwaysHidden
is VERY poorly named indeed. It should perhaps be calledignoreInitialFocus
instead.UPDATE: More ways to get a window token
If there is no focused view (e.g. can happen if you just changed fragments), there are other views that will supply a useful window token.
These are alternatives for the above code
if (view == null) view = new View(activity);
These don't refer explicitly to your activity.Inside a fragment class:
Given a fragment
fragment
as a parameter:Starting from your content body:
UPDATE 2: Clear focus to avoid showing keyboard again if you open the app from the background
Add this line to the end of the method:
view.clearFocus();
对于隐藏软键盘也很有用:
这可以用于抑制软键盘,直到用户实际触摸 editText 视图。
Also useful for hiding the soft-keyboard is:
This can be used to suppress the soft-keyboard until the user actually touches the editText View.
我还有另一种隐藏键盘的解决方案:
这里在
showFlag
位置传递HIDE_IMPLICIT_ONLY
,在hiddenFlag
位置传递0
代码>.它将强制关闭软键盘。I got one more solution to hide keyboard:
Here pass
HIDE_IMPLICIT_ONLY
at the position ofshowFlag
and0
at the position ofhiddenFlag
. It will forcefully close soft Keyboard.迈耶的解决方案也适合我。就我而言,我的应用程序的顶层是选项卡主机,我想在切换选项卡时隐藏关键字 - 我从选项卡主机视图获取窗口令牌。
Meier's solution works for me too. In my case, the top level of my App is a tab host and I want to hide the keyword when switching tabs - I get the window token from the tab host View.
请在
onCreate()
中尝试以下代码Please try this below code in
onCreate()
更新:
我不知道为什么这个解决方案不再起作用(我刚刚在 Android 23 上进行了测试)。请改用 Saurabh Pareek 的解决方案。这是:
旧答案:
Update:
I don't know why this solution is not work any more ( I just tested on Android 23). Please use the solution of Saurabh Pareek instead. Here it is:
Old answer:
如果这里的所有其他答案都不适合您,那么还有另一种手动控制键盘的方法。
创建一个函数来管理
EditText
的一些属性:然后,确保您打开/关闭键盘的
EditText
的 onFocus:现在,只要您愿意手动打开键盘调用:
关闭调用:
If all the other answers here don't work for you as you would like them to, there's another way of manually controlling the keyboard.
Create a function with that will manage some of the
EditText
's properties:Then, make sure that onFocus of the
EditText
you open/close the keyboard:Now, whenever you want to open the keyboard manually call:
And for closing call:
Saurabh Pareek 是迄今为止最好的答案。
不过,不妨使用正确的标志。
实际使用示例
Saurabh Pareek has the best answer so far.
Might as well use the correct flags, though.
Example of real use
通过如此搜索,我在这里找到了适合我的答案
from so searching, here I found an answer that works for me
简短的回答
在您的
OnClick
侦听器中,使用IME_ACTION_DONE
调用EditText
的onEditorAction
进行深入分析,
我觉得这样方法更好、更简单、更符合Android的设计模式。
在上面的简单示例中(通常在大多数常见情况下),您将拥有一个具有焦点的
EditText
,并且它通常也是首先调用键盘的那个(它在许多常见场景中肯定能够调用它)。同样,it 应该是释放键盘的人,通常可以通过ImeAction
来完成。只需看看EditText
与android:imeOptions="actionDone"
的行为方式即可,您希望通过相同的方式实现相同的行为。检查此相关答案
The short answer
In your
OnClick
listener call theonEditorAction
of theEditText
withIME_ACTION_DONE
The drill-down
I feel this method is better, simpler and more aligned with Android's design pattern.
In the simple example above (and usually in most of the common cases) you'll have an
EditText
that has/had focus and it also usually was the one to invoke the keyboard in the first place (it is definitely able to invoke it in many common scenarios). In that same way, it should be the one to release the keyboard, usually that can be done by anImeAction
. Just see how anEditText
withandroid:imeOptions="actionDone"
behaves, you want to achieve the same behavior by the same means.Check this related answer
感谢上帝,它在11 年后得到了官方支持。
首先将依赖项
implementation 'androidx.core:core-ktx:1.7.0'
添加到应用程序 gradle。然后从 ViewCompat 或 WindowCompat 类获取 InsetsController。
最后使用 InsetsController 的 hide() 和 show() 函数
添加对 Dialog 的支持。在 BottomSheetDialog 中可用。 @Rondev。
使用更安全的方式来获取活动,而不是直接从上下文中转换。
下面的旧答案
这是 github 上的简单项目
Thank God it’s officially supported after 11 years.
First add dependency
implementation 'androidx.core:core-ktx:1.7.0'
to app gradle.Then get InsetsController from ViewCompat or WindowCompat class.
Finally use hide() and show() function of InsetsController
Add support for Dialog. Available in BottomSheetDialog. @Rondev.
Using a safer way to get activity instead of directly cast from context.
Old anwser below
Here is the simple project on github
这应该有效:
This should work:
我正在使用自定义键盘输入十六进制数字,因此无法显示 IMM 键盘...
在 v3.2.4_r1 中添加了
setSoftInputShownOnFocus(boolean show)
来控制天气或不控制天气当 TextView 获得焦点时显示键盘,但它仍然隐藏,因此必须使用反射:对于旧版本,我使用
OnGlobalLayoutListener
获得了非常好的结果(但远非完美),并添加了从我的根视图中借助 ViewTreeObserver ,然后检查键盘是否显示如下:最后一个解决方案可能会瞬间显示键盘并与选择手柄混淆。
当键盘进入全屏时,不会调用 onGlobalLayout。为了避免这种情况,请使用 TextView#setImeOptions(int) 或在 TextView XML 声明中:
更新: 刚刚发现什么对话框用于从不显示键盘并且适用于所有版本:
I'm using a custom keyboard to input an Hex number so I can't have the IMM keyboard show up...
In v3.2.4_r1
setSoftInputShownOnFocus(boolean show)
was added to control weather or not to display the keyboard when a TextView gets focus, but its still hidden so reflection must be used:For older versions, I got very good results (but far from perfect) with a
OnGlobalLayoutListener
, added with the aid of aViewTreeObserver
from my root view and then checking if the keyboard is shown like this:This last solution may show the keyboard for a split second and messes with the selection handles.
When in the keyboard enters full screen, onGlobalLayout isn't called. To avoid that, use TextView#setImeOptions(int) or in the TextView XML declaration:
Update: Just found what dialogs use to never show the keyboard and works in all versions:
现在,差不多 12 年后,我们终于有了一个官方的、向后兼容的方法来做到这一点 AndroidX Core 1.5+:
或专门用于 Fragment:
Now, almost 12 years later, we finally have an official, backwards compatible way to do this with AndroidX Core 1.5+:
or specifically for Fragment:
我花了两天多的时间研究了帖子中发布的所有解决方案,发现它们在某种程度上有所缺乏。我的具体要求是有一个按钮能够 100% 可靠地显示或隐藏屏幕键盘。当键盘处于隐藏状态时,无论用户单击哪个输入字段,都不应重新出现。当它处于可见状态时,无论用户单击什么按钮,键盘都不应消失。这需要在 Android 2.2+ 一直到最新的设备上运行。
您可以在我的应用中看到此功能的有效实现 干净的 RPN。
在许多不同的手机(包括 froyo 和姜饼设备)上测试了许多建议的答案后,很明显 Android 应用程序可以可靠地:
聚焦一个新的文本字段。
并在活动上设置一个标志,指示他们键盘应该
始终可见。仅当活动处于活动状态时才能设置此标志
正在初始化。
键盘。仅当活动处于活动状态时才能设置此标志
正在初始化。
对我来说,暂时隐藏键盘是不够的。在某些设备上,一旦新的文本字段获得焦点,它就会重新出现。由于我的应用程序在一页上使用多个文本字段,因此聚焦新的文本字段将导致隐藏的键盘再次弹出。
不幸的是,列表中的第 2 项和第 3 项仅在活动开始时才具有可靠性。一旦活动变得可见,您就无法永久隐藏或显示键盘。诀窍是当用户按下键盘切换按钮时实际重新启动您的活动。在我的应用程序中,当用户按下切换键盘按钮时,将运行以下代码:
这会导致当前活动将其状态保存到捆绑包中,然后启动该活动,传递一个布尔值,该布尔值指示键盘是否应该被按下。显示或隐藏。
在 onCreate 方法中,运行以下代码:
如果应显示软键盘,则告知 InputMethodManager 显示键盘,并指示窗口使软输入始终可见。如果应隐藏软键盘,则设置 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM。
这种方法在我测试过的所有设备上都能可靠地工作——从运行 android 2.2 的 4 年历史的 HTC 手机到运行 4.2.2 的 Nexus 7。这种方法的唯一缺点是您需要小心处理后退按钮。由于我的应用程序基本上只有一个屏幕(它是一个计算器),我可以覆盖 onBackPressed() 并返回到设备主屏幕。
I have spent more than two days working through all of the solutions posted in the thread and have found them lacking in one way or another. My exact requirement is to have a button that will with 100% reliability show or hide the on screen keyboard. When the keyboard is in its hidden state is should not re-appear, no matter what input fields the user clicks on. When it is in its visible state the keyboard should not disappear no matter what buttons the user clicks. This needs to work on Android 2.2+ all the way up to the latest devices.
You can see a working implementation of this in my app clean RPN.
After testing many of the suggested answers on a number of different phones (including froyo and gingerbread devices) it became apparent that android apps can reliably:
focuses a new text field.
and set a flag on the activity indicating that they keyboard should
always be visible. This flag can only be set when an activity is
initialising.
keyboard. This flag can only be set when an activity is
initialising.
For me, temporarily hiding the keyboard is not enough. On some devices it will re-appear as soon as a new text field is focused. As my app uses multiple text fields on one page, focusing a new text field will cause the hidden keyboard to pop back up again.
Unfortunately item 2 and 3 on the list only work reliability when an activity is being started. Once the activity has become visible you cannot permanently hide or show the keyboard. The trick is to actually restart your activity when the user presses the keyboard toggle button. In my app when the user presses on the toggle keyboard button, the following code runs:
This causes the current activity to have its state saved into a Bundle, and then the activity is started, passing through an boolean which indicates if the keyboard should be shown or hidden.
Inside the onCreate method the following code is run:
If the soft keyboard should be shown, then the InputMethodManager is told to show the keyboard and the window is instructed to make the soft input always visible. If the soft keyboard should be hidden then the WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM is set.
This approach works reliably on all devices I have tested on - from a 4 year old HTC phone running android 2.2 up to a nexus 7 running 4.2.2. The only disadvantage with this approach is you need to be careful with handling the back button. As my app essentially only has one screen (its a calculator) I can override onBackPressed() and return to the devices home screen.
如果您想从任何地方关闭软键盘,则可以替代这种全方位解决方案对用于打开键盘的 (EditText) 字段的引用,但如果该字段获得焦点,仍然想要执行此操作,您可以使用它(来自活动):
Alternatively to this all around solution, if you wanted to close the soft keyboard from anywhere without having a reference to the (EditText) field that was used to open the keyboard, but still wanted to do it if the field was focused, you could use this (from an Activity):
感谢 这个答案,我得出了以下内容,就我而言,在滚动浏览 a 的片段时效果很好查看分页器...
Thanks to this SO answer, I derived the following which, in my case, works nicely when scrolling through the the fragments of a ViewPager...
上面的答案适用于不同的场景,但是如果您想将键盘隐藏在视图内并努力获取正确的上下文,请尝试以下操作:
并获取上下文,从构造函数中获取它:)
Above answers work for different scenario's but If you want to hide the keyboard inside a view and struggling to get the right context try this:
and to get the context fetch it from constructor:)
如果您想在单元或功能测试期间关闭软键盘,可以通过单击测试中的“后退按钮”来实现:
我将“后退按钮”放在引号中,因为上面不会触发
onBackPressed()
对于有问题的 Activity。它只是关闭键盘。确保在继续之前暂停一会儿,因为关闭后退按钮需要一点时间,因此后续对视图等的点击只有在短暂的暂停后才会被注册(1秒就足够长了) )。
If you want to close the soft keyboard during a unit or functional test, you can do so by clicking the "back button" from your test:
I put "back button" in quotes, since the above doesn't trigger the
onBackPressed()
for the Activity in question. It just closes the keyboard.Make sure to pause for a little while before moving on, since it takes a little while to close the back button, so subsequent clicks to Views, etc., won't be registered until after a short pause (1 second is long enough ime).
以下是在 Android 版 Mono(又名 MonoDroid)中的操作方法
Here's how you do it in Mono for Android (AKA MonoDroid)
这对我所有奇怪的键盘行为都有效
This worked for me for all the bizarre keyboard behavior
方法简单易用,只需调用 hideKeyboardFrom(YourActivity.this); 即可隐藏键盘
Simple and Easy to use method, just call hideKeyboardFrom(YourActivity.this); to hide keyboard
通过扩展函数实现 Kotlin 版本
使用 Kotlin 扩展函数,显示和隐藏软键盘变得如此简单。
ExtensionFunctions.kt
用法
现在,在您的
Activity
或Fragment
中,hideKeyboard()
可以清晰地访问并调用它来自EditText
的实例,例如:Kotlin version via an extension function
Using Kotlin extension functions, it'd be so simple to show and hide the soft keyboard.
ExtensionFunctions.kt
Usage
Now in your
Activity
orFragment
,hideKeyboard()
is clearly accessible as well as calling it from an instance ofEditText
like:只需在您的活动中使用此优化代码:
Just use this optimized code in your activity:
在清单文件中添加到您的活动
android:windowSoftInputMode="stateHidden"
中。例子:Add to your activity
android:windowSoftInputMode="stateHidden"
in Manifest file. Example:对于打开键盘:
对于关闭/隐藏键盘:
For Open Keyboard :
For Close/Hide Keyboard :
我有这样的情况,我的
EditText
也可以位于AlertDialog
中,因此键盘应该在关闭时关闭。以下代码似乎在任何地方都可以工作:I have the case, where my
EditText
can be located also in anAlertDialog
, so the keyboard should be closed on dismiss. The following code seems to be working anywhere: