Skip to content

Instantly share code, notes, and snippets.

@TemMax
Last active October 8, 2020 09:51
Show Gist options
  • Save TemMax/4f4931208e6b39b8c49f6e6ca751e006 to your computer and use it in GitHub Desktop.
Save TemMax/4f4931208e6b39b8c49f6e6ca751e006 to your computer and use it in GitHub Desktop.
Keyboard-aware FrameLayout that fits when keyboard is opened. 100 dp is a magic dimension. Waiting for WindowInsets update with Android 11
import android.content.Context
import android.util.AttributeSet
import android.widget.FrameLayout
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
/**
* Before adding this:
* 1. In AndroidManifest in your <activity/> tag android:windowSoftInputMode="adjustResize"
* 2. Enable "EDGE-TO-EDGE" mode in your activity -> window.decorView.systemUiVisibility = decorView.systemUiVisibility or (View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
* 2.1. Set colors for status and navigation bars:
* window.statusBarColor = [yourColor]
* window.navigationBarColor = [yourColor]
* 2.2. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
* window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
* }
* 3. Profit
*/
typealias KeyboardStateListener = (isShowed: Boolean) -> Unit
class SizeNotifierFrameLayout @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
private companion object {
private val minKeyboardSize = Screen.dp(100)
}
private var keyboardStateListener: KeyboardStateListener? = null
private var keyboardSize = 0
set(value) {
field = value
keyboardStateListener?.invoke(isKeyboardShowed)
}
val isKeyboardShowed: Boolean
get() = keyboardSize > minKeyboardSize
var isUpdatePaddingWhenKeyboardShowed = true
init {
doOnApplyWindowInsets { _, insets, initialPadding ->
if (isUpdatePaddingWhenKeyboardShowed) {
updatePadding(bottom = initialPadding.bottom + insets.systemWindowInsetBottom)
}
keyboardSize = insets.systemWindowInsetBottom
insets
}
}
fun setKeyboardStateListener(listener: KeyboardStateListener?) {
this.keyboardStateListener = listener
}
}
fun View.doOnApplyWindowInsets(block: (View, insets: WindowInsetsCompat, initialPadding: Rect) -> WindowInsetsCompat) {
val initialPadding = recordInitialPaddingForView(this)
ViewCompat.setOnApplyWindowInsetsListener(this) { v, insets ->
block(v, insets, initialPadding)
}
requestApplyInsetsWhenAttached()
}
private fun recordInitialPaddingForView(view: View) =
Rect(view.paddingLeft, view.paddingTop, view.paddingRight, view.paddingBottom)
private fun View.requestApplyInsetsWhenAttached() {
if (isAttachedToWindow) {
ViewCompat.requestApplyInsets(this)
} else {
addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
override fun onViewAttachedToWindow(v: View) {
v.removeOnAttachStateChangeListener(this)
ViewCompat.requestApplyInsets(v)
}
override fun onViewDetachedFromWindow(v: View) = Unit
})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment