用 Kotlin 关闭/隐藏 Android 软键盘

我正在 Kotlin 写一个简单的安卓应用程序。我的布局中有一个 EditText 和一个 Button。在编辑字段并单击 Button 之后,我想隐藏虚拟键盘。

有一个 最常见的问题关闭/隐藏 Android 软键盘关于在 Java 中做这件事,但就我所知,应该有一个替代版本的 Kotlin。我该怎么做?

95629 次浏览

You can use Anko to make life easier, so the line would be:

inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)

or maybe better to create extension function:

fun View.hideKeyboard(inputMethodManager: InputMethodManager) {
inputMethodManager.hideSoftInputFromWindow(windowToken, 0)
}

and call it like this:

view?.hideKeyboard(activity.inputMethodManager)

I think we can improve Viktor's answer a little. Based on it always being attached to a View, there will be context, and if there is context then there is InputMethodManager:

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

In this case the context automatically means the context of the view. What do you think?

Peter's solution solves neatly the problem by extending functionality of View class. Alternative approach could be to extend functionality of Activity class and thus bind operation of hiding keyboard with View's container rather than View itself.

fun Activity.hideKeyboard() {
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(findViewById(android.R.id.content).getWindowToken(), 0);
}

Use the following utility functions within your Activities, Fragments to hide the soft keyboard.

(*)Update for the latest Kotlin version

fun Fragment.hideKeyboard() {
view?.let { activity?.hideKeyboard(it) }
}


fun Activity.hideKeyboard() {
hideKeyboard(currentFocus ?: View(this))
}


fun Context.hideKeyboard(view: View) {
val inputMethodManager = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)
}

This will close the keyboard regardless of your code either in dialog fragment and/or activity etc.

Usage in Activity/Fragment:

hideKeyboard()

This works well with API 26.

val view: View = if (currentFocus == null) View(this) else currentFocus
val inputMethodManager = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)

I found the answer that worked for me here: http://programminget.blogspot.com/2017/08/how-to-close-android-soft-keyboard.html

val inputManager:InputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
inputManager.hideSoftInputFromWindow(currentFocus.windowToken, InputMethodManager.SHOW_FORCED)

You can use from bellow code, I write bellow code in my fragment:

private val myLayout = ViewTreeObserver.OnGlobalLayoutListener {
yourTextView.isCursorVisible = KeyboardTool.isSoftKeyboardShown(myRelativeLayout.rootView)
}

Then in onViewCreated of fragment:

......
super.onViewCreated(view, savedInstanceState)
myRelativeLayout.viewTreeObserver.addOnGlobalLayoutListener(myLayout)
......

And in onDestroyView use too:

override fun onDestroyView() {
super.onDestroyView()
myRelativeLayout.viewTreeObserver.removeOnGlobalLayoutListener(myLayout)
}

And:

object KeyboardTool {
fun isSoftKeyboardShown(rootView: View): Boolean {
val softKeyboardHeight = 100
val rect = Rect()


rootView.getWindowVisibleDisplayFrame(rect)


val dm = rootView.resources.displayMetrics
val heightDiff = rootView.bottom - rect.bottom
return heightDiff > softKeyboardHeight * dm.density
}
}

Make an object class named Utils:

object Utils {


fun hideSoftKeyBoard(context: Context, view: View) {
try {
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm?.hideSoftInputFromWindow(view.windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
} catch (e: Exception) {
// TODO: handle exception
e.printStackTrace()
}


}
}

You can use this method in any class where you want to hide the soft input keyboard. I am using this in my BaseActivity.

Here the view is any view that you use in your layout:

Utils.hideSoftKeyBoard(this@BaseActivity, view )

Simply override this method in your activity. It will automatically works in its child fragments as well.....

In JAVA

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (getCurrentFocus() != null) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}
return super.dispatchTouchEvent(ev);
}

In Kotlin

override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
if (currentFocus != null) {
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(currentFocus!!.windowToken, 0)
}
return super.dispatchTouchEvent(ev)
}

In your Activity or Fragment create a function as:

fun View.hideKeyboard() {
val inputManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
inputManager.hideSoftInputFromWindow(windowToken, 0)
}

suppose you have a button with an id your_button_id in XML file related to this Activity or Fragment, so, on button click event:

    your_button_id.setOnClickListener{
it.hideKeyboard()
}

Here is my solution in Kotlin for Fragment. Place it inside setOnClickListener of the button.

val imm = context?.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager?
imm?.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0)

Thanks to @Zeeshan Ayaz Here is a little improved version

Because 'currentFocus' is nullable we better check it using Kotlin's ?.let

override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
currentFocus?.let { currFocus ->
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(currFocus.windowToken, 0)
}
return super.dispatchTouchEvent(ev)
}

Kotlin I use bellow code:

import splitties.systemservices.inputMethodManager

inputMethodManager.hideSoftInputFromWindow(view?.windowToken, 0)

Although there are many answers but this answer is related to a best practice in KOTLIN by opening and closing the keyboard with life cycle and extension function.

1). Create Extension Functions create a file EditTextExtension.kt and paste the below code

fun EditText.showKeyboard(
) {
requestFocus()
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as
InputMethodManager
imm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT)
}


fun EditText.hideKeyboard(
) {
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as
InputMethodManager
imm.hideSoftInputFromWindow(this.windowToken, 0)
}

2). Create LifeCycleObserver Class Create a class EditTextKeyboardLifecycleObserver.kt and paste the code below

class EditTextKeyboardLifecycleObserver(
private val editText: WeakReference<EditText>
) :
LifecycleObserver {


@OnLifecycleEvent(
Lifecycle.Event.ON_RESUME
)
fun openKeyboard() {
editText.get()?.postDelayed({ editText.get()?.showKeyboard() }, 50)
}
fun hideKeyboard() {
editText.get()?.postDelayed({ editText.get()?.hideKeyboard() }, 50)
}
}

3). Then use the below code in onViewCreated / onCreateView

lifecycle.addObserver(
EditTextKeyboardLifecycleObserver(
WeakReference(mEditText) //mEditText is the object(EditText)
)
)

The Keyboard will open when the user opens the fragment or activity.

if you occur any problems, following the solution feel free to ask in the comment.

I didn't see this variant of Kotlin extension function:

fun View.hideSoftInput() {
val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(windowToken, 0)
}

Its benefit is that this extension function could be called from every CustomView and in every click or touch listener

Write a function to hide the keyboard:

private fun hideKeyboard(){
// since our app extends AppCompatActivity, it has access to context
val imm=getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
// we have to tell hide the keyboard from what. inorder to do is we have to pass window token
// all of our views,like message, name, button have access to same window token. since u have button
imm.hideSoftInputFromWindow(button.windowToken, 0)


// if you are using binding object
// imm.hideSoftInputFromWindow(binding.button.windowToken,0)


}

You have to call this function whereever u need

You can use a Function Extension in Kotlin. Replace activity by fragment if you need make it in Fragment.

fun Activity.hideKeyboard() {
hideKeyboard(currentFocus ?: View(this))
}