Created
August 26, 2020 15:49
-
-
Save fabirt/470040b4e7dcfa89bf4b42c1c01955fa to your computer and use it in GitHub Desktop.
Android 11 WindowInsets API Demo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.example.windowinsets | |
| import android.graphics.Insets | |
| import androidx.appcompat.app.AppCompatActivity | |
| import android.os.Bundle | |
| import android.view.View | |
| import android.view.WindowInsets | |
| import android.view.WindowInsetsAnimation | |
| import androidx.recyclerview.widget.LinearLayoutManager | |
| import kotlinx.android.synthetic.main.activity_main.* | |
| // Android 11 WindowInsets API Demo | |
| class MainActivity : AppCompatActivity() { | |
| companion object { | |
| const val TAG = "MainActivityLog" | |
| } | |
| override fun onCreate(savedInstanceState: Bundle?) { | |
| super.onCreate(savedInstanceState) | |
| setContentView(R.layout.activity_main) | |
| window.setDecorFitsSystemWindows(false) | |
| recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, true) | |
| recyclerView.adapter = MyAdapter() | |
| val rootView = window.decorView.rootView | |
| val deferringInsetsListener = RootViewDeferringInsetsCallback( | |
| persistentInsetTypes = WindowInsets.Type.systemBars(), | |
| deferredInsetTypes = WindowInsets.Type.ime() | |
| ) | |
| rootView.setWindowInsetsAnimationCallback(deferringInsetsListener) | |
| rootView.setOnApplyWindowInsetsListener(deferringInsetsListener) | |
| editText.setWindowInsetsAnimationCallback(TranslateDeferringInsetsAnimationCallback( | |
| view = editText, | |
| persistentInsetTypes = WindowInsets.Type.systemBars(), | |
| deferredInsetTypes = WindowInsets.Type.ime(), | |
| dispatchMode = WindowInsetsAnimation.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE | |
| )) | |
| recyclerView.setWindowInsetsAnimationCallback(TranslateDeferringInsetsAnimationCallback( | |
| view = recyclerView, | |
| persistentInsetTypes = WindowInsets.Type.systemBars(), | |
| deferredInsetTypes = WindowInsets.Type.ime() | |
| )) | |
| } | |
| } | |
| class RootViewDeferringInsetsCallback( | |
| val persistentInsetTypes: Int, | |
| val deferredInsetTypes: Int | |
| ) : WindowInsetsAnimation.Callback(DISPATCH_MODE_CONTINUE_ON_SUBTREE), View.OnApplyWindowInsetsListener { | |
| private var view: View? = null | |
| private var lastWindowInsets: WindowInsets? = null | |
| private var deferredInsets = false | |
| override fun onProgress( | |
| insets: WindowInsets, | |
| runningAnimations: List<WindowInsetsAnimation> | |
| ): WindowInsets { | |
| return insets | |
| } | |
| override fun onApplyWindowInsets(v: View?, windowInsets: WindowInsets?): WindowInsets { | |
| view = v | |
| lastWindowInsets = windowInsets | |
| val types = when { | |
| deferredInsets -> persistentInsetTypes | |
| else -> persistentInsetTypes or deferredInsetTypes | |
| } | |
| val typeInsets = windowInsets!!.getInsets(types) | |
| v?.setPadding(typeInsets.left, typeInsets.top, typeInsets.right, typeInsets.bottom) | |
| return WindowInsets.CONSUMED | |
| } | |
| override fun onPrepare(animation: WindowInsetsAnimation) { | |
| if (animation.typeMask and deferredInsetTypes != 0) { | |
| deferredInsets = true | |
| } | |
| } | |
| override fun onEnd(animation: WindowInsetsAnimation) { | |
| if (deferredInsets && (animation.typeMask and deferredInsetTypes) != 0) { | |
| deferredInsets = false | |
| if (lastWindowInsets != null) { | |
| view?.dispatchApplyWindowInsets(lastWindowInsets!!) | |
| } | |
| } | |
| } | |
| } | |
| class TranslateDeferringInsetsAnimationCallback( | |
| private val view: View, | |
| val persistentInsetTypes: Int, | |
| val deferredInsetTypes: Int, | |
| dispatchMode: Int = DISPATCH_MODE_STOP | |
| ) : WindowInsetsAnimation.Callback(dispatchMode) { | |
| init { | |
| require(persistentInsetTypes and deferredInsetTypes == 0) { | |
| "persistentInsetTypes and deferredInsetTypes can not contain any of " + | |
| " same WindowInsets.Type values" | |
| } | |
| } | |
| override fun onProgress( | |
| insets: WindowInsets, | |
| runningAnimations: List<WindowInsetsAnimation> | |
| ): WindowInsets { | |
| val typesInset = insets.getInsets(deferredInsetTypes) | |
| val otherInset = insets.getInsets(persistentInsetTypes) | |
| val diff = Insets.subtract(typesInset, otherInset).let { | |
| Insets.max(it, Insets.NONE) | |
| } | |
| view.translationX = (diff.left - diff.right).toFloat() | |
| view.translationY = (diff.top - diff.bottom).toFloat() | |
| return insets | |
| } | |
| override fun onEnd(animation: WindowInsetsAnimation) { | |
| view.translationX = 0f | |
| view.translationY = 0f | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment