Better BottomNavigationView hide/unhide animation
This commit is contained in:
parent
e7f700ee9a
commit
95e39e4f4c
2 changed files with 87 additions and 8 deletions
|
@ -366,18 +366,15 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val translationY =
|
|
||||||
if (visible) 0F else dip(R.dimen.bottom_nav_height).toFloat() + windowInsets.safeGetBottomInsets()
|
|
||||||
val mAnimate = animate && bottomSheetBehavior.state == STATE_COLLAPSED
|
val mAnimate = animate && bottomSheetBehavior.state == STATE_COLLAPSED
|
||||||
if (mAnimate) {
|
if (mAnimate) {
|
||||||
binding.bottomNavigationView.translateYAnimate(translationY).doOnEnd {
|
if (visible) {
|
||||||
if (visible && bottomSheetBehavior.state != STATE_EXPANDED) {
|
binding.bottomNavigationView.bringToFront()
|
||||||
binding.bottomNavigationView.bringToFront()
|
binding.bottomNavigationView.show()
|
||||||
}
|
} else {
|
||||||
|
binding.bottomNavigationView.hide()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
binding.bottomNavigationView.translationY =
|
|
||||||
translationY
|
|
||||||
binding.bottomNavigationView.isVisible = false
|
binding.bottomNavigationView.isVisible = false
|
||||||
if (visible && bottomSheetBehavior.state != STATE_EXPANDED) {
|
if (visible && bottomSheetBehavior.state != STATE_EXPANDED) {
|
||||||
binding.bottomNavigationView.bringToFront()
|
binding.bottomNavigationView.bringToFront()
|
||||||
|
|
|
@ -16,10 +16,13 @@ package code.name.monkey.retromusic.extensions
|
||||||
|
|
||||||
import android.animation.Animator
|
import android.animation.Animator
|
||||||
import android.animation.ObjectAnimator
|
import android.animation.ObjectAnimator
|
||||||
|
import android.animation.ValueAnimator
|
||||||
|
import android.graphics.drawable.BitmapDrawable
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.ViewTreeObserver
|
import android.view.ViewTreeObserver
|
||||||
|
import android.view.animation.AnimationUtils
|
||||||
import android.view.inputmethod.InputMethodManager
|
import android.view.inputmethod.InputMethodManager
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import androidx.annotation.LayoutRes
|
import androidx.annotation.LayoutRes
|
||||||
|
@ -32,6 +35,7 @@ import code.name.monkey.appthemehelper.ThemeStore
|
||||||
import code.name.monkey.appthemehelper.util.TintHelper
|
import code.name.monkey.appthemehelper.util.TintHelper
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
import code.name.monkey.retromusic.util.RetroUtil
|
import code.name.monkey.retromusic.util.RetroUtil
|
||||||
|
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
import dev.chrisbanes.insetter.applyInsetter
|
import dev.chrisbanes.insetter.applyInsetter
|
||||||
|
|
||||||
|
@ -58,6 +62,84 @@ fun EditText.appHandleColor(): EditText {
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Potentially animate showing a [BottomNavigationView].
|
||||||
|
*
|
||||||
|
* Abruptly changing the visibility leads to a re-layout of main content, animating
|
||||||
|
* `translationY` leaves a gap where the view was that content does not fill.
|
||||||
|
*
|
||||||
|
* Instead, take a snapshot of the view, and animate this in, only changing the visibility (and
|
||||||
|
* thus layout) when the animation completes.
|
||||||
|
*/
|
||||||
|
fun BottomNavigationView.show() {
|
||||||
|
if (isVisible) return
|
||||||
|
|
||||||
|
val parent = parent as ViewGroup
|
||||||
|
// View needs to be laid out to create a snapshot & know position to animate. If view isn't
|
||||||
|
// laid out yet, need to do this manually.
|
||||||
|
if (!isLaidOut) {
|
||||||
|
measure(
|
||||||
|
View.MeasureSpec.makeMeasureSpec(parent.width, View.MeasureSpec.EXACTLY),
|
||||||
|
View.MeasureSpec.makeMeasureSpec(parent.height, View.MeasureSpec.AT_MOST)
|
||||||
|
)
|
||||||
|
layout(parent.left, parent.height - measuredHeight, parent.right, parent.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
val drawable = BitmapDrawable(context.resources, drawToBitmap())
|
||||||
|
drawable.setBounds(left, parent.height, right, parent.height + height)
|
||||||
|
parent.overlay.add(drawable)
|
||||||
|
ValueAnimator.ofInt(parent.height, top).apply {
|
||||||
|
duration = 300
|
||||||
|
interpolator = AnimationUtils.loadInterpolator(
|
||||||
|
context,
|
||||||
|
android.R.interpolator.linear_out_slow_in
|
||||||
|
)
|
||||||
|
addUpdateListener {
|
||||||
|
val newTop = it.animatedValue as Int
|
||||||
|
drawable.setBounds(left, newTop, right, newTop + height)
|
||||||
|
}
|
||||||
|
doOnEnd {
|
||||||
|
parent.overlay.remove(drawable)
|
||||||
|
isVisible = true
|
||||||
|
}
|
||||||
|
start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Potentially animate hiding a [BottomNavigationView].
|
||||||
|
*
|
||||||
|
* Abruptly changing the visibility leads to a re-layout of main content, animating
|
||||||
|
* `translationY` leaves a gap where the view was that content does not fill.
|
||||||
|
*
|
||||||
|
* Instead, take a snapshot, instantly hide the view (so content lays out to fill), then animate
|
||||||
|
* out the snapshot.
|
||||||
|
*/
|
||||||
|
fun BottomNavigationView.hide() {
|
||||||
|
if (isGone) return
|
||||||
|
|
||||||
|
val drawable = BitmapDrawable(context.resources, drawToBitmap())
|
||||||
|
val parent = parent as ViewGroup
|
||||||
|
drawable.setBounds(left, top, right, bottom)
|
||||||
|
parent.overlay.add(drawable)
|
||||||
|
isGone = true
|
||||||
|
ValueAnimator.ofInt(top, parent.height).apply {
|
||||||
|
duration = 300L
|
||||||
|
interpolator = AnimationUtils.loadInterpolator(
|
||||||
|
context,
|
||||||
|
android.R.interpolator.fast_out_linear_in
|
||||||
|
)
|
||||||
|
addUpdateListener {
|
||||||
|
val newTop = it.animatedValue as Int
|
||||||
|
drawable.setBounds(left, newTop, right, newTop + height)
|
||||||
|
}
|
||||||
|
doOnEnd {
|
||||||
|
parent.overlay.remove(drawable)
|
||||||
|
}
|
||||||
|
start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun View.translateYAnimate(value: Float): Animator {
|
fun View.translateYAnimate(value: Float): Animator {
|
||||||
return ObjectAnimator.ofFloat(this, "translationY", value)
|
return ObjectAnimator.ofFloat(this, "translationY", value)
|
||||||
.apply {
|
.apply {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue