Skip to content

Instantly share code, notes, and snippets.

@am3n
Created July 11, 2019 08:39
Show Gist options
  • Save am3n/6a06a41449099b41376568759a4de6a3 to your computer and use it in GitHub Desktop.
Save am3n/6a06a41449099b41376568759a4de6a3 to your computer and use it in GitHub Desktop.
Listen to keyboard open/close in android with LiveData
package com.example
import android.annotation.SuppressLint
import android.app.Activity
import android.graphics.Rect
import android.view.View
import android.view.ViewTreeObserver
import androidx.lifecycle.LiveData
import java.lang.ref.WeakReference
@SuppressLint("StaticFieldLeak")
class KeyboardManager private constructor() : LiveData<KeyboardManager.KeyboardStatus>() {
companion object {
private var instance: KeyboardManager? = null
fun init(activity: Activity): KeyboardManager {
if (instance == null)
instance = KeyboardManager(activity)
return instance!!
}
}
private constructor(activity: Activity) : this() {
activityWeakReference?.get()?.let {
return
}
if (activityWeakReference==null)
activityWeakReference = WeakReference(activity)
}
private var activityWeakReference: WeakReference<Activity>? = null
private var rootView: View? = null
private var globalLayoutListener: ViewTreeObserver.OnGlobalLayoutListener? = null
fun status(): KeyboardManager? {
if (instance == null)
throw IllegalAccessException("Call init with activity reference before accessing status")
return instance
}
private fun addOnGlobalLayoutListener() {
activityWeakReference?.get()?.let {
rootView = rootView ?: it.findViewById(android.R.id.content)
globalLayoutListener = ViewTreeObserver.OnGlobalLayoutListener {
val rect = Rect().apply { rootView!!.getWindowVisibleDisplayFrame(this) }
val screenHeight = rootView!!.height
// rect.bottom is the position above soft keypad or device button.
// if keypad is shown, the rect.bottom is smaller than that before.
val keypadHeight = screenHeight - rect.bottom
// 0.15 ratio is perhaps enough to determine keypad height.
if (Math.abs(keypadHeight) > screenHeight * 0.05) {
postValue(KeyboardStatus.OPEN)
} else {
postValue(KeyboardStatus.CLOSED)
}
}
rootView!!.viewTreeObserver.addOnGlobalLayoutListener(globalLayoutListener)
}
}
private fun removeOnGlobalLayoutListener() {
rootView?.viewTreeObserver?.removeOnGlobalLayoutListener(globalLayoutListener)
rootView = null
globalLayoutListener = null
}
override fun onActive() {
super.onActive()
addOnGlobalLayoutListener()
}
override fun onInactive() {
super.onInactive()
removeOnGlobalLayoutListener()
}
enum class KeyboardStatus {
OPEN, CLOSED
}
}
package com.example.ui.main
...
...
...
class MainActivity : AppCompatActivity(), Observer<KeyboardManager.KeyboardStatus> {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
...
}
override fun onResume() {
super.onResume()
KeyboardManager.init(this).status()?.observeForever(this)
...
}
override fun onChanged(status: KeyboardManager.KeyboardStatus?) {
Log.d("Meeeeee", status?.name)
if (status == KeyboardManager.KeyboardStatus.CLOSED) {
// todo, on closed
} else {
// todo, on opened
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment