Skip to content

Instantly share code, notes, and snippets.

@tim4dev
Last active April 29, 2022 04:39
Show Gist options
  • Save tim4dev/eb268617942317fdbf7d299aa9727757 to your computer and use it in GitHub Desktop.
Save tim4dev/eb268617942317fdbf7d299aa9727757 to your computer and use it in GitHub Desktop.
Android keyboard state observer.
/**
* Android keyboard state observer.
* For portrait orientation only.
* https://bit.ly/3flvZar
* 2020 intelligence.worker@gmail.com.
*
* Example of usage:
* viewLifecycleOwner.lifecycleScope.launch {
* this@MyFragment.view?.run {
* KeyboardObserver().observe(your_root_view_here).distinctUntilChanged().collect { ... }
* }
* }
*/
class KeyboardObserver {
private var mRootView: View? = null
fun observe(rootView: View): Flow<KeyboardData> = callbackFlow {
mRootView = rootView
val listener = ViewTreeObserver.OnGlobalLayoutListener {
mRootView?.run {
val rootHeight = rootView.height
val rect = Rect().apply { rootView.getWindowVisibleDisplayFrame(this) }
val keyboardHeight = rootHeight - (rect.bottom - rect.top)
if (keyboardHeight > rootHeight * MIN_KEYBOARD_HEIGHT_RATIO) {
offer(KeyboardData(KeyboardStatus.OPENED, keyboardHeight))
} else {
offer(KeyboardData(KeyboardStatus.CLOSED, keyboardHeight))
}
}
}
mRootView?.viewTreeObserver?.addOnGlobalLayoutListener(listener)
awaitClose {
mRootView?.viewTreeObserver?.removeOnGlobalLayoutListener(listener)
}
}
companion object {
// ratio is perhaps enough to determine keypad height
const val MIN_KEYBOARD_HEIGHT_RATIO = 0.15
}
}
enum class KeyboardStatus {
OPENED, CLOSED
}
data class KeyboardData(
val status: KeyboardStatus,
val keyboardHeight: Int
) {
val isClosed: Boolean
get() = status == KeyboardStatus.CLOSED
val isOpened: Boolean
get() = status == KeyboardStatus.OPENED
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment