@@ -228,7 +228,7 @@ fun SmallTopAppBar(
228228fun MiuixScrollBehavior (
229229 state : TopAppBarState = rememberTopAppBarState(),
230230 canScroll : () -> Boolean = { true },
231- snapAnimationSpec : AnimationSpec <Float >? = spring(stiffness = 3000f ),
231+ snapAnimationSpec : AnimationSpec <Float >? = spring(stiffness = 2500f ),
232232 flingAnimationSpec : DecayAnimationSpec <Float >? = rememberSplineBasedDecay()
233233): ScrollBehavior =
234234 remember(state, canScroll, snapAnimationSpec, flingAnimationSpec) {
@@ -424,10 +424,13 @@ private class ExitUntilCollapsedScrollBehavior(
424424 override var nestedScrollConnection =
425425 object : NestedScrollConnection {
426426 override fun onPreScroll (available : Offset , source : NestedScrollSource ): Offset {
427+ // Don't intercept if scrolling down.
427428 if (! canScroll() || available.y > 0 ) return Offset .Zero
428429 val prevHeightOffset = state.heightOffset
429- state.heightOffset + = available.y
430+ state.heightOffset = state.heightOffset + available.y
430431 return if (prevHeightOffset != state.heightOffset) {
432+ // We're in the middle of top app bar collapse or expand.
433+ // Consume only the scroll on the Y axis.
431434 available.copy(x = 0f )
432435 } else {
433436 Offset .Zero
@@ -439,25 +442,35 @@ private class ExitUntilCollapsedScrollBehavior(
439442 available : Offset ,
440443 source : NestedScrollSource ,
441444 ): Offset {
442- if (! canScroll() || available.y < 0 ) return Offset .Zero
445+ if (! canScroll()) return Offset .Zero
443446 state.contentOffset + = consumed.y
444- val oldHeightOffset = state.heightOffset
445- state.heightOffset + = available.y
446- return Offset (0f , state.heightOffset - oldHeightOffset)
447- }
448447
449- override suspend fun onPreFling (available : Velocity ): Velocity {
450- if (available.y < 0 && state.heightOffset < 0f ) {
451- return settleAppBar(state, available.y, flingAnimationSpec, snapAnimationSpec)
448+ if (available.y < 0f || consumed.y < 0f ) {
449+ // When scrolling up, just update the state's height offset.
450+ val oldHeightOffset = state.heightOffset
451+ state.heightOffset = state.heightOffset + consumed.y
452+ return Offset (0f , state.heightOffset - oldHeightOffset)
453+ }
454+
455+ if (available.y > 0f ) {
456+ // Adjust the height offset in case the consumed delta Y is less than what was
457+ // recorded as available delta Y in the pre-scroll.
458+ val oldHeightOffset = state.heightOffset
459+ state.heightOffset = state.heightOffset + available.y
460+ return Offset (0f , state.heightOffset - oldHeightOffset)
452461 }
453- return Velocity .Zero
462+ return Offset .Zero
454463 }
455464
456465 override suspend fun onPostFling (consumed : Velocity , available : Velocity ): Velocity {
457466 if (available.y > 0 ) {
458- return settleAppBar(state, available.y, flingAnimationSpec, snapAnimationSpec)
467+ // Reset the total content offset to zero when scrolling all the way down. This
468+ // will eliminate some float precision inaccuracies.
469+ state.contentOffset = 0f
459470 }
460- return Velocity .Zero
471+ val superConsumed = super .onPostFling(consumed, available)
472+ return superConsumed +
473+ settleAppBar(state, available.y, flingAnimationSpec, snapAnimationSpec)
461474 }
462475 }
463476}
@@ -484,10 +497,16 @@ private suspend fun settleAppBar(
484497 flingAnimationSpec : DecayAnimationSpec <Float >? ,
485498 snapAnimationSpec : AnimationSpec <Float >? ,
486499): Velocity {
500+ // Check if the app bar is completely collapsed/expanded. If so, no need to settle the app bar,
501+ // and just return Zero Velocity.
502+ // Note that we don't check for 0f due to float precision with the collapsedFraction
503+ // calculation.
487504 if (state.collapsedFraction < 0.01f || state.collapsedFraction == 1f ) {
488505 return Velocity .Zero
489506 }
490507 var remainingVelocity = velocity
508+ // In case there is an initial velocity that was left after a previous user fling, animate to
509+ // continue the motion to expand or collapse the app bar.
491510 if (flingAnimationSpec != null && abs(velocity) > 1f ) {
492511 var lastValue = 0f
493512 AnimationState (initialValue = 0f , initialVelocity = velocity).animateDecay(
@@ -503,6 +522,7 @@ private suspend fun settleAppBar(
503522 if (abs(delta - consumed) > 0.5f ) this .cancelAnimation()
504523 }
505524 }
525+ // Snap if animation specs were provided.
506526 if (snapAnimationSpec != null ) {
507527 if (state.heightOffset < 0 && state.heightOffset > state.heightOffsetLimit) {
508528 AnimationState (initialValue = state.heightOffset).animateTo(
@@ -515,7 +535,6 @@ private suspend fun settleAppBar(
515535 ) {
516536 state.heightOffset = value
517537 }
518- return Velocity (0f , velocity - remainingVelocity)
519538 }
520539 }
521540 return Velocity (0f , velocity - remainingVelocity)
@@ -860,4 +879,4 @@ private fun SmallTopAppBarLayout(
860879 )
861880 }
862881 }
863- }
882+ }
0 commit comments