diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/widgets/HideBottomNavigationOnScrollBehavior.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/widgets/HideBottomNavigationOnScrollBehavior.kt index 0dbdd37f8..7d92ffad4 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/widgets/HideBottomNavigationOnScrollBehavior.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/widgets/HideBottomNavigationOnScrollBehavior.kt @@ -8,7 +8,7 @@ import android.view.animation.DecelerateInterpolator import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.view.ViewCompat import com.google.android.material.appbar.AppBarLayout -import com.google.android.material.bottomnavigation.BottomNavigationView +import com.google.android.material.navigation.NavigationBarView import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.util.ext.getAnimationDuration import org.koitharu.kotatsu.core.util.ext.measureHeight @@ -16,7 +16,7 @@ import org.koitharu.kotatsu.core.util.ext.measureHeight class HideBottomNavigationOnScrollBehavior @JvmOverloads constructor( context: Context? = null, attrs: AttributeSet? = null, -) : CoordinatorLayout.Behavior(context, attrs) { +) : CoordinatorLayout.Behavior(context, attrs) { @ViewCompat.NestedScrollType private var lastStartedType: Int = 0 @@ -34,13 +34,13 @@ class HideBottomNavigationOnScrollBehavior @JvmOverloads constructor( } } - override fun layoutDependsOn(parent: CoordinatorLayout, child: BottomNavigationView, dependency: View): Boolean { + override fun layoutDependsOn(parent: CoordinatorLayout, child: NavigationBarView, dependency: View): Boolean { return dependency is AppBarLayout } override fun onDependentViewChanged( parent: CoordinatorLayout, - child: BottomNavigationView, + child: NavigationBarView, dependency: View, ): Boolean { val appBarSize = dependency.measureHeight() @@ -54,7 +54,7 @@ class HideBottomNavigationOnScrollBehavior @JvmOverloads constructor( override fun onStartNestedScroll( coordinatorLayout: CoordinatorLayout, - child: BottomNavigationView, + child: NavigationBarView, directTargetChild: View, target: View, axes: Int, @@ -70,7 +70,7 @@ class HideBottomNavigationOnScrollBehavior @JvmOverloads constructor( override fun onNestedPreScroll( coordinatorLayout: CoordinatorLayout, - child: BottomNavigationView, + child: NavigationBarView, target: View, dx: Int, dy: Int, @@ -85,7 +85,7 @@ class HideBottomNavigationOnScrollBehavior @JvmOverloads constructor( override fun onStopNestedScroll( coordinatorLayout: CoordinatorLayout, - child: BottomNavigationView, + child: NavigationBarView, target: View, type: Int, ) { @@ -94,7 +94,7 @@ class HideBottomNavigationOnScrollBehavior @JvmOverloads constructor( } } - private fun animateBottomNavigationVisibility(child: BottomNavigationView, isVisible: Boolean) { + private fun animateBottomNavigationVisibility(child: NavigationBarView, isVisible: Boolean) { offsetAnimator?.cancel() offsetAnimator = ValueAnimator().apply { interpolator = DecelerateInterpolator() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/widgets/SlidingBottomNavigationView.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/widgets/SlidingBottomNavigationView.kt index c7413a149..5f400ae28 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/widgets/SlidingBottomNavigationView.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/widgets/SlidingBottomNavigationView.kt @@ -3,10 +3,12 @@ package org.koitharu.kotatsu.core.ui.widgets import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.animation.TimeInterpolator +import android.annotation.SuppressLint import android.content.Context import android.os.Parcel import android.os.Parcelable import android.util.AttributeSet +import android.view.MotionEvent import android.view.ViewPropertyAnimator import androidx.annotation.AttrRes import androidx.annotation.StyleRes @@ -15,9 +17,11 @@ import androidx.core.view.isVisible import androidx.customview.view.AbsSavedState import androidx.interpolator.view.animation.FastOutLinearInInterpolator import androidx.interpolator.view.animation.LinearOutSlowInInterpolator -import com.google.android.material.bottomnavigation.BottomNavigationView +import com.google.android.material.bottomnavigation.BottomNavigationMenuView +import com.google.android.material.navigation.NavigationBarView import org.koitharu.kotatsu.core.util.ext.applySystemAnimatorScale import org.koitharu.kotatsu.core.util.ext.measureHeight +import kotlin.math.max import com.google.android.material.R as materialR private const val STATE_DOWN = 1 @@ -26,12 +30,14 @@ private const val STATE_UP = 2 private const val SLIDE_UP_ANIMATION_DURATION = 225L private const val SLIDE_DOWN_ANIMATION_DURATION = 175L +private const val MAX_ITEM_COUNT = 6 + class SlidingBottomNavigationView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = materialR.attr.bottomNavigationStyle, @StyleRes defStyleRes: Int = materialR.style.Widget_Design_BottomNavigationView, -) : BottomNavigationView(context, attrs, defStyleAttr, defStyleRes), +) : NavigationBarView(context, attrs, defStyleAttr, defStyleRes), CoordinatorLayout.AttachedBehavior { private var currentAnimator: ViewPropertyAnimator? = null @@ -55,6 +61,49 @@ class SlidingBottomNavigationView @JvmOverloads constructor( return behavior } + /** From BottomNavigationView **/ + + @SuppressLint("ClickableViewAccessibility") + override fun onTouchEvent(event: MotionEvent): Boolean { + super.onTouchEvent(event) + // Consume all events to avoid views under the BottomNavigationView from receiving touch events. + return true + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + val minHeightSpec = makeMinHeightSpec(heightMeasureSpec) + super.onMeasure(widthMeasureSpec, minHeightSpec) + if (MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY) { + setMeasuredDimension( + measuredWidth, + max( + measuredHeight, + suggestedMinimumHeight + paddingTop + paddingBottom, + ), + ) + } + } + + private fun makeMinHeightSpec(measureSpec: Int): Int { + var minHeight = suggestedMinimumHeight + if (MeasureSpec.getMode(measureSpec) != MeasureSpec.EXACTLY && minHeight > 0) { + minHeight += paddingTop + paddingBottom + + return MeasureSpec.makeMeasureSpec( + max(MeasureSpec.getSize(measureSpec), minHeight), MeasureSpec.AT_MOST, + ) + } + + return measureSpec + } + + override fun getMaxItemCount(): Int = MAX_ITEM_COUNT + + @SuppressLint("RestrictedApi") + override fun createNavigationBarMenuView(context: Context) = BottomNavigationMenuView(context) + + /** End **/ + override fun onSaveInstanceState(): Parcelable { val superState = super.onSaveInstanceState() return SavedState(superState, currentState, translationY)