Updated navigation behavior to be consistent and easily manageable
This commit is contained in:
parent
67b5f39df2
commit
b8b0f257db
@ -3,14 +3,12 @@ package com.topjohnwu.magisk.redesign
|
|||||||
import android.graphics.Insets
|
import android.graphics.Insets
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.ViewGroup
|
import android.view.View
|
||||||
import android.view.ViewTreeObserver
|
import android.view.ViewTreeObserver
|
||||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.core.view.setPadding
|
import androidx.core.view.setPadding
|
||||||
import androidx.core.view.updateLayoutParams
|
import androidx.core.view.updateLayoutParams
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
|
|
||||||
import com.google.android.material.card.MaterialCardView
|
import com.google.android.material.card.MaterialCardView
|
||||||
import com.ncapdevi.fragnav.FragNavController
|
import com.ncapdevi.fragnav.FragNavController
|
||||||
import com.topjohnwu.magisk.Const
|
import com.topjohnwu.magisk.Const
|
||||||
@ -25,6 +23,7 @@ import com.topjohnwu.magisk.redesign.module.ModuleFragment
|
|||||||
import com.topjohnwu.magisk.redesign.superuser.SuperuserFragment
|
import com.topjohnwu.magisk.redesign.superuser.SuperuserFragment
|
||||||
import com.topjohnwu.magisk.utils.HideBottomViewOnScrollBehavior
|
import com.topjohnwu.magisk.utils.HideBottomViewOnScrollBehavior
|
||||||
import com.topjohnwu.magisk.utils.HideTopViewOnScrollBehavior
|
import com.topjohnwu.magisk.utils.HideTopViewOnScrollBehavior
|
||||||
|
import com.topjohnwu.magisk.utils.HideableBehavior
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
@ -84,10 +83,9 @@ open class MainActivity : CompatActivity<MainViewModel, ActivityMainMd2Binding>(
|
|||||||
|
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
onTabTransaction(null, -1)
|
onTabTransaction(null, -1)
|
||||||
onFragmentTransaction(null, FragNavController.TransactionType.PUSH)
|
|
||||||
|
|
||||||
if (!navigation.isRoot) {
|
if (!navigation.isRoot) {
|
||||||
requestNavigationHidden(animate = false)
|
requestNavigationHidden()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,19 +112,13 @@ open class MainActivity : CompatActivity<MainViewModel, ActivityMainMd2Binding>(
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onTabTransaction(fragment: Fragment?, index: Int) {
|
override fun onTabTransaction(fragment: Fragment?, index: Int) =
|
||||||
setDisplayHomeAsUpEnabled(false)
|
onFragmentTransaction(fragment, FragNavController.TransactionType.PUSH)
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFragmentTransaction(
|
override fun onFragmentTransaction(
|
||||||
fragment: Fragment?,
|
fragment: Fragment?,
|
||||||
transactionType: FragNavController.TransactionType
|
transactionType: FragNavController.TransactionType
|
||||||
) {
|
) {
|
||||||
binding.mainToolbarWrapper.animate()
|
|
||||||
.translationY(0f)
|
|
||||||
.setInterpolator(FastOutSlowInInterpolator())
|
|
||||||
.start()
|
|
||||||
|
|
||||||
setDisplayHomeAsUpEnabled(!navigation.isRoot)
|
setDisplayHomeAsUpEnabled(!navigation.isRoot)
|
||||||
requestNavigationHidden(!navigation.isRoot)
|
requestNavigationHidden(!navigation.isRoot)
|
||||||
}
|
}
|
||||||
@ -143,25 +135,19 @@ open class MainActivity : CompatActivity<MainViewModel, ActivityMainMd2Binding>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun requestNavigationHidden(hide: Boolean = true, animate: Boolean = true) {
|
@Suppress("UNCHECKED_CAST")
|
||||||
val lapam = binding.mainBottomBar.layoutParams as ViewGroup.MarginLayoutParams
|
internal fun requestNavigationHidden(hide: Boolean = true) {
|
||||||
val height = binding.mainBottomBar.measuredHeight
|
val topView = binding.mainToolbarWrapper
|
||||||
val verticalMargin = lapam.let { it.topMargin + it.bottomMargin }
|
val bottomView = binding.mainBottomBar
|
||||||
val maxTranslation = height + verticalMargin
|
|
||||||
val translation = if (!hide) 0 else maxTranslation
|
|
||||||
|
|
||||||
if (!animate) {
|
val topParams = topView.layoutParams as? CoordinatorLayout.LayoutParams
|
||||||
binding.mainBottomBar.translationY = translation.toFloat()
|
val bottomParams = bottomView.layoutParams as? CoordinatorLayout.LayoutParams
|
||||||
binding.mainBottomBar.isVisible = !hide
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.mainBottomBar.animate()
|
val topBehavior = topParams?.behavior as? HideableBehavior<View>
|
||||||
.translationY(translation.toFloat())
|
val bottomBehavior = bottomParams?.behavior as? HideableBehavior<View>
|
||||||
.setInterpolator(FastOutSlowInInterpolator())
|
|
||||||
.withStartAction { if (!hide) binding.mainBottomBar.isVisible = true }
|
topBehavior?.setHidden(topView, hide = false, lockState = false)
|
||||||
.withEndAction { if (hide) binding.mainBottomBar.isVisible = false }
|
bottomBehavior?.setHidden(bottomView, hide, hide)
|
||||||
.start()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun invalidateToolbar() {
|
fun invalidateToolbar() {
|
||||||
|
@ -11,14 +11,17 @@ import com.google.android.material.snackbar.Snackbar
|
|||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
class HideBottomViewOnScrollBehavior<T : View> : HideBottomViewOnScrollBehavior<T>() {
|
class HideBottomViewOnScrollBehavior<V : View> : HideBottomViewOnScrollBehavior<V>(),
|
||||||
|
HideableBehavior<V> {
|
||||||
|
|
||||||
override fun layoutDependsOn(parent: CoordinatorLayout, child: T, dependency: View) =
|
private var lockState: Boolean = false
|
||||||
|
|
||||||
|
override fun layoutDependsOn(parent: CoordinatorLayout, child: V, dependency: View) =
|
||||||
super.layoutDependsOn(parent, child, dependency) or (dependency is Snackbar.SnackbarLayout)
|
super.layoutDependsOn(parent, child, dependency) or (dependency is Snackbar.SnackbarLayout)
|
||||||
|
|
||||||
override fun onDependentViewChanged(
|
override fun onDependentViewChanged(
|
||||||
parent: CoordinatorLayout,
|
parent: CoordinatorLayout,
|
||||||
child: T,
|
child: V,
|
||||||
dependency: View
|
dependency: View
|
||||||
) = when (dependency) {
|
) = when (dependency) {
|
||||||
is Snackbar.SnackbarLayout -> onDependentViewChanged(parent, child, dependency)
|
is Snackbar.SnackbarLayout -> onDependentViewChanged(parent, child, dependency)
|
||||||
@ -27,7 +30,7 @@ class HideBottomViewOnScrollBehavior<T : View> : HideBottomViewOnScrollBehavior<
|
|||||||
|
|
||||||
override fun onDependentViewRemoved(
|
override fun onDependentViewRemoved(
|
||||||
parent: CoordinatorLayout,
|
parent: CoordinatorLayout,
|
||||||
child: T,
|
child: V,
|
||||||
dependency: View
|
dependency: View
|
||||||
) = when (dependency) {
|
) = when (dependency) {
|
||||||
is Snackbar.SnackbarLayout -> onDependentViewRemoved(parent, child, dependency)
|
is Snackbar.SnackbarLayout -> onDependentViewRemoved(parent, child, dependency)
|
||||||
@ -38,7 +41,7 @@ class HideBottomViewOnScrollBehavior<T : View> : HideBottomViewOnScrollBehavior<
|
|||||||
|
|
||||||
private fun onDependentViewChanged(
|
private fun onDependentViewChanged(
|
||||||
parent: CoordinatorLayout,
|
parent: CoordinatorLayout,
|
||||||
child: T,
|
child: V,
|
||||||
dependency: Snackbar.SnackbarLayout
|
dependency: Snackbar.SnackbarLayout
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val viewMargin = (child.layoutParams as ViewGroup.MarginLayoutParams).bottomMargin
|
val viewMargin = (child.layoutParams as ViewGroup.MarginLayoutParams).bottomMargin
|
||||||
@ -58,7 +61,7 @@ class HideBottomViewOnScrollBehavior<T : View> : HideBottomViewOnScrollBehavior<
|
|||||||
|
|
||||||
private fun onDependentViewRemoved(
|
private fun onDependentViewRemoved(
|
||||||
parent: CoordinatorLayout,
|
parent: CoordinatorLayout,
|
||||||
child: T,
|
child: V,
|
||||||
dependency: Snackbar.SnackbarLayout
|
dependency: Snackbar.SnackbarLayout
|
||||||
) {
|
) {
|
||||||
// checks whether the navigation is not hidden via scroll
|
// checks whether the navigation is not hidden via scroll
|
||||||
@ -69,6 +72,36 @@ class HideBottomViewOnScrollBehavior<T : View> : HideBottomViewOnScrollBehavior<
|
|||||||
|
|
||||||
//---
|
//---
|
||||||
|
|
||||||
|
override fun slideUp(child: V) {
|
||||||
|
if (lockState) return
|
||||||
|
super.slideUp(child)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun slideDown(child: V) {
|
||||||
|
if (lockState) return
|
||||||
|
super.slideDown(child)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setHidden(
|
||||||
|
view: V,
|
||||||
|
hide: Boolean,
|
||||||
|
lockState: Boolean
|
||||||
|
) {
|
||||||
|
if (!lockState) {
|
||||||
|
this.lockState = lockState
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hide) {
|
||||||
|
slideDown(view)
|
||||||
|
} else {
|
||||||
|
slideUp(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lockState = lockState
|
||||||
|
}
|
||||||
|
|
||||||
|
//---
|
||||||
|
|
||||||
private fun View.translationY(destination: Float) = animate()
|
private fun View.translationY(destination: Float) = animate()
|
||||||
.translationY(destination)
|
.translationY(destination)
|
||||||
.setInterpolator(FastOutSlowInInterpolator())
|
.setInterpolator(FastOutSlowInInterpolator())
|
||||||
|
@ -10,7 +10,8 @@ import androidx.core.view.ViewCompat
|
|||||||
import com.google.android.material.animation.AnimationUtils
|
import com.google.android.material.animation.AnimationUtils
|
||||||
import com.google.android.material.behavior.HideBottomViewOnScrollBehavior
|
import com.google.android.material.behavior.HideBottomViewOnScrollBehavior
|
||||||
|
|
||||||
class HideTopViewOnScrollBehavior<V : View> : HideBottomViewOnScrollBehavior<V>() {
|
class HideTopViewOnScrollBehavior<V : View> : HideBottomViewOnScrollBehavior<V>(),
|
||||||
|
HideableBehavior<V> {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val STATE_SCROLLED_DOWN = 1
|
private const val STATE_SCROLLED_DOWN = 1
|
||||||
@ -21,6 +22,7 @@ class HideTopViewOnScrollBehavior<V : View> : HideBottomViewOnScrollBehavior<V>(
|
|||||||
private var currentState = STATE_SCROLLED_UP
|
private var currentState = STATE_SCROLLED_UP
|
||||||
private var additionalHiddenOffsetY = 0
|
private var additionalHiddenOffsetY = 0
|
||||||
private var currentAnimator: ViewPropertyAnimator? = null
|
private var currentAnimator: ViewPropertyAnimator? = null
|
||||||
|
private var lockState: Boolean = false
|
||||||
|
|
||||||
override fun onLayoutChild(
|
override fun onLayoutChild(
|
||||||
parent: CoordinatorLayout,
|
parent: CoordinatorLayout,
|
||||||
@ -63,10 +65,30 @@ class HideTopViewOnScrollBehavior<V : View> : HideBottomViewOnScrollBehavior<V>(
|
|||||||
dxUnconsumed: Int,
|
dxUnconsumed: Int,
|
||||||
dyUnconsumed: Int
|
dyUnconsumed: Int
|
||||||
) {
|
) {
|
||||||
when {
|
// when initiating scroll while the view is at the bottom or at the top and pushing it
|
||||||
dyConsumed > 0 -> slideUp(child)
|
// further, the parent will report consumption of 0
|
||||||
dyConsumed < 0 -> slideDown(child)
|
if (dyConsumed == 0) return
|
||||||
|
|
||||||
|
setHidden(child, dyConsumed > 0, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun setHidden(
|
||||||
|
view: V,
|
||||||
|
hide: Boolean,
|
||||||
|
lockState: Boolean
|
||||||
|
) {
|
||||||
|
if (!lockState) {
|
||||||
|
this.lockState = lockState
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hide) {
|
||||||
|
slideUp(view)
|
||||||
|
} else {
|
||||||
|
slideDown(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lockState = lockState
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -74,7 +96,7 @@ class HideTopViewOnScrollBehavior<V : View> : HideBottomViewOnScrollBehavior<V>(
|
|||||||
* screen.
|
* screen.
|
||||||
*/
|
*/
|
||||||
override fun slideDown(child: V) {
|
override fun slideDown(child: V) {
|
||||||
if (currentState == STATE_SCROLLED_UP) {
|
if (currentState == STATE_SCROLLED_UP || lockState) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +119,7 @@ class HideTopViewOnScrollBehavior<V : View> : HideBottomViewOnScrollBehavior<V>(
|
|||||||
* screen.
|
* screen.
|
||||||
*/
|
*/
|
||||||
override fun slideUp(child: V) {
|
override fun slideUp(child: V) {
|
||||||
if (currentState == STATE_SCROLLED_DOWN) {
|
if (currentState == STATE_SCROLLED_DOWN || lockState) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.topjohnwu.magisk.utils
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
|
||||||
|
interface HideableBehavior<V : View> {
|
||||||
|
|
||||||
|
fun setHidden(view: V, hide: Boolean, lockState: Boolean = false)
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user