73

I'm trying to write a simple Android app in Kotlin. 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.

There is a popular question Close/hide the Android Soft Keyboard about doing it in Java, but as far as I understand, there should be an alternative version for Kotlin. How should I do it?

Community
  • 1
  • 1
Eugene Trifonov
  • 831
  • 1
  • 7
  • 7

15 Answers15

146

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()
Gunhan
  • 5,433
  • 2
  • 37
  • 33
  • 1
    Where would you recommend these three functions live in the application? – Dan Jul 24 '18 at 21:18
  • 3
    @Dan I keep these functions in ContextExtensions.kt file of mine but you can keep them anywhere you find suitable. – Gunhan Jul 25 '18 at 10:45
  • This worked perfectly for me. Funny thing is I only needed this code when the app was running on a physical device. On the simulator (AVD) the keyboard dismissed itself like a good keyboard does. – Dan Jul 26 '18 at 14:10
  • For some reason when I put these in a ContextExtensions.kt file, I can't seem to access them from my Fragments, etc.. Is there something special I need to setup in the ContextExtensions class in order to make these accessible across the app? – svguerin3 May 15 '19 at 18:38
  • @svguerin3 It should work directly. Only thing that I can think of is that if you're using multi module android project I'm not so sure if you can access Kotlin Extensions which is defined in another module. But also try to clean/rebuild. – Gunhan May 16 '19 at 10:56
  • For Activity: hideKeyboard(currentFocus ?: View(this)) – CeH9 Oct 27 '19 at 18:26
  • @CeH9 Yeah, shorter is better – Gunhan Oct 28 '19 at 11:36
  • 1
    OMG thanks SO much for this. Coming from iOS, it seems ridiculous to me that this is even a problem but your solution is the cleanest I've seen. Thank you! – Ricky Padilla Sep 21 '20 at 18:26
  • not able to use these in functions, any help regarding their calling ? – Karan Khurana Sep 23 '20 at 20:31
  • They need to be called using an activity, fragment, or context reference if you're not directly calling them inside fragment or activity. – Gunhan Sep 24 '20 at 07:46
76

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?

Josh Correia
  • 2,133
  • 1
  • 17
  • 29
Péter Szűcs
  • 955
  • 8
  • 15
18

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)
    }
Kaushik
  • 6,017
  • 5
  • 33
  • 51
Zeeshan Ayaz
  • 337
  • 2
  • 6
6

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);
}
michal.z
  • 1,951
  • 1
  • 13
  • 10
5

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)
Viktor Yakunin
  • 2,777
  • 3
  • 21
  • 34
5

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()
     }
Seddiq Sorush
  • 1,381
  • 13
  • 16
4

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 )
Andrew Fan
  • 1,214
  • 4
  • 17
  • 24
3

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)
Kaushik
  • 6,017
  • 5
  • 33
  • 51
2

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)
Scooter
  • 3,807
  • 4
  • 28
  • 44
1

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)
Kavin Varnan
  • 1,871
  • 17
  • 22
1

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)
}
Akbolat SSS
  • 960
  • 9
  • 15
0

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
    }
}
jo jo
  • 1,186
  • 2
  • 7
  • 24
0

Kotlin I use bellow code:

import splitties.systemservices.inputMethodManager

inputMethodManager.hideSoftInputFromWindow(view?.windowToken, 0)

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.

MRazaImtiaz
  • 716
  • 4
  • 18
0

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

MeLine
  • 1,590
  • 4
  • 20
  • 32