Added layout behavior to dismiss toolbars when scrolling

This commit is contained in:
Viktor De Pasquale 2019-10-16 16:08:07 +02:00
parent 51247d36c5
commit 2daa131fb2
4 changed files with 140 additions and 1 deletions

View File

@ -3,8 +3,11 @@ package com.topjohnwu.magisk.redesign
import android.graphics.Insets
import android.os.Bundle
import android.view.ViewTreeObserver
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.setPadding
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment
import com.google.android.material.card.MaterialCardView
import com.ncapdevi.fragnav.FragNavController
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.R
@ -16,6 +19,7 @@ import com.topjohnwu.magisk.ui.log.LogFragment
import com.topjohnwu.magisk.ui.module.ModulesFragment
import com.topjohnwu.magisk.ui.settings.SettingsFragment
import com.topjohnwu.magisk.ui.superuser.SuperuserFragment
import com.topjohnwu.magisk.utils.HideTopViewOnScrollBehavior
import com.topjohnwu.superuser.Shell
import org.koin.androidx.viewmodel.ext.android.viewModel
import kotlin.reflect.KClass
@ -48,6 +52,9 @@ open class MainActivity : CompatActivity<MainViewModel, ActivityMainMd2Binding>(
setSupportActionBar(binding.mainToolbar)
binding.mainToolbarWrapper.updateLayoutParams<CoordinatorLayout.LayoutParams> {
behavior = HideTopViewOnScrollBehavior<MaterialCardView>()
}
binding.mainNavigation.setOnNavigationItemSelectedListener {
when (it.itemId) {
R.id.homeFragment -> Navigation.home()

View File

@ -0,0 +1,130 @@
package com.topjohnwu.magisk.utils
import android.animation.TimeInterpolator
import android.view.View
import android.view.ViewGroup
import android.view.ViewPropertyAnimator
import androidx.annotation.Dimension
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.ViewCompat
import com.google.android.material.animation.AnimationUtils
import com.google.android.material.behavior.HideBottomViewOnScrollBehavior
class HideTopViewOnScrollBehavior<V : View> : HideBottomViewOnScrollBehavior<V>() {
companion object {
private const val STATE_SCROLLED_DOWN = 1
private const val STATE_SCROLLED_UP = 2
}
private var height = 0
private var currentState = STATE_SCROLLED_UP
private var additionalHiddenOffsetY = 0
private var currentAnimator: ViewPropertyAnimator? = null
override fun onLayoutChild(
parent: CoordinatorLayout,
child: V,
layoutDirection: Int
): Boolean {
val paramsCompat = child.layoutParams as ViewGroup.MarginLayoutParams
height = child.measuredHeight + paramsCompat.topMargin
return super.onLayoutChild(parent, child, layoutDirection)
}
/**
* Sets an additional offset for the y position used to hide the view.
*
* @param child the child view that is hidden by this behavior
* @param offset the additional offset in pixels that should be added when the view slides away
*/
override fun setAdditionalHiddenOffsetY(child: V, @Dimension offset: Int) {
additionalHiddenOffsetY = offset
if (currentState == STATE_SCROLLED_DOWN) {
child.translationY = (height + additionalHiddenOffsetY).toFloat()
}
}
override fun onStartNestedScroll(
coordinatorLayout: CoordinatorLayout,
child: V,
directTargetChild: View,
target: View,
nestedScrollAxes: Int
) = nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL
override fun onNestedScroll(
coordinatorLayout: CoordinatorLayout,
child: V,
target: View,
dxConsumed: Int,
dyConsumed: Int,
dxUnconsumed: Int,
dyUnconsumed: Int
) {
when {
dyConsumed > 0 -> slideUp(child)
dyConsumed < 0 -> slideDown(child)
}
}
/**
* Perform an animation that will slide the child from it's current position to be totally on the
* screen.
*/
override fun slideDown(child: V) {
if (currentState == STATE_SCROLLED_UP) {
return
}
currentAnimator?.let {
it.cancel()
child.clearAnimation()
}
currentState = STATE_SCROLLED_UP
animateChildTo(
child,
0,
ENTER_ANIMATION_DURATION.toLong(),
AnimationUtils.LINEAR_OUT_SLOW_IN_INTERPOLATOR
)
}
/**
* Perform an animation that will slide the child from it's current position to be totally off the
* screen.
*/
override fun slideUp(child: V) {
if (currentState == STATE_SCROLLED_DOWN) {
return
}
currentAnimator?.let {
it.cancel()
child.clearAnimation()
}
currentState = STATE_SCROLLED_DOWN
animateChildTo(
child,
-(height + additionalHiddenOffsetY),
EXIT_ANIMATION_DURATION.toLong(),
AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR
)
}
private fun animateChildTo(
child: V,
targetY: Int,
duration: Long,
interpolator: TimeInterpolator
) = child
.animate()
.translationY(targetY.toFloat())
.setInterpolator(interpolator)
.setDuration(duration)
.withEndAction { currentAnimator = null }
.let { currentAnimator = it }
}

View File

@ -28,6 +28,7 @@
style="?styleCardElevated"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/main_toolbar_wrapper"
android:layout_marginStart="@dimen/l1"
android:layout_marginTop="@{(int) @dimen/l1 + viewModel.insets.top}"
android:layout_marginEnd="@dimen/l1"
@ -55,6 +56,7 @@
style="?styleCardElevated"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"
android:layout_gravity="bottom"
android:layout_marginStart="@dimen/l1"
android:layout_marginEnd="@dimen/l1"

View File

@ -22,7 +22,7 @@
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size + (int) @dimen/l2}"
android:paddingBottom="@{viewModel.insets.bottom + (int) @dimen/margin_fab + (int) @dimen/l1}"
android:paddingBottom="@{viewModel.insets.bottom + (int) @dimen/l1}"
tools:layout_marginTop="24dp">
<LinearLayout