From ab42e1b139f87f0d8cb05f7f72c455f6c171dc40 Mon Sep 17 00:00:00 2001 From: RareScrap Date: Sun, 7 Nov 2021 15:44:56 +0300 Subject: [PATCH 01/11] appbar snapping implementation for ExitUntilCollapsed scroll strategy + Extracted defaults --- .../me/onebone/toolbar/ParallaxActivity.kt | 1 + .../me/onebone/toolbar/AppBarContainer.kt | 4 +-- .../me/onebone/toolbar/CollapsingToolbar.kt | 15 +++++++--- .../toolbar/CollapsingToolbarScaffold.kt | 3 +- .../java/me/onebone/toolbar/ScrollStrategy.kt | 30 ++++++++++++------- .../java/me/onebone/toolbar/SnapStrategy.kt | 21 +++++++++++++ .../onebone/toolbar/ToolbarWithFabScaffold.kt | 2 ++ 7 files changed, 59 insertions(+), 17 deletions(-) create mode 100644 lib/src/main/java/me/onebone/toolbar/SnapStrategy.kt diff --git a/app/src/main/java/me/onebone/toolbar/ParallaxActivity.kt b/app/src/main/java/me/onebone/toolbar/ParallaxActivity.kt index a6dcdd9..b567a82 100644 --- a/app/src/main/java/me/onebone/toolbar/ParallaxActivity.kt +++ b/app/src/main/java/me/onebone/toolbar/ParallaxActivity.kt @@ -66,6 +66,7 @@ fun ParallaxEffect() { modifier = Modifier.fillMaxSize(), state = state, scrollStrategy = ScrollStrategy.EnterAlwaysCollapsed, + snapStrategy = SnapStrategy(), toolbarModifier = Modifier.background(MaterialTheme.colors.primary), toolbar = { // Collapsing toolbar collapses its size as small as the that of diff --git a/lib/src/main/java/me/onebone/toolbar/AppBarContainer.kt b/lib/src/main/java/me/onebone/toolbar/AppBarContainer.kt index 9c2f30f..6418d8d 100644 --- a/lib/src/main/java/me/onebone/toolbar/AppBarContainer.kt +++ b/lib/src/main/java/me/onebone/toolbar/AppBarContainer.kt @@ -40,7 +40,6 @@ import androidx.compose.ui.layout.Placeable import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.Density import kotlin.math.max -import kotlin.math.roundToInt @Deprecated( "Use AppBarContainer for naming consistency", @@ -81,9 +80,10 @@ fun AppBarContainer( ) { val offsetY = remember { mutableStateOf(0) } val flingBehavior = ScrollableDefaults.flingBehavior() + val snapStrategy = null val (scope, measurePolicy) = remember(scrollStrategy, collapsingToolbarState) { - AppbarContainerScopeImpl(scrollStrategy.create(offsetY, collapsingToolbarState, flingBehavior)) to + AppbarContainerScopeImpl(scrollStrategy.create(offsetY, collapsingToolbarState, flingBehavior, snapStrategy)) to AppbarMeasurePolicy(scrollStrategy, collapsingToolbarState, offsetY) } diff --git a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbar.kt b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbar.kt index a9958ee..1914930 100644 --- a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbar.kt +++ b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbar.kt @@ -57,7 +57,7 @@ import kotlin.math.roundToInt @Stable class CollapsingToolbarState( - initial: Int = Int.MAX_VALUE + initial: Int = CollapsingToolbarDefaults.INITIAL_HEIGHT ): ScrollableState { /** * [height] indicates current height of the toolbar. @@ -137,7 +137,7 @@ class CollapsingToolbarState( fun feedScroll(value: Float): Float = dispatchRawDelta(value) @ExperimentalToolbarApi - suspend fun expand(duration: Int = 200) { + suspend fun expand(duration: Int = CollapsingToolbarDefaults.EXPAND_DURATION) { val anim = AnimationState(height.toFloat()) scroll { @@ -150,7 +150,7 @@ class CollapsingToolbarState( } @ExperimentalToolbarApi - suspend fun collapse(duration: Int = 200) { + suspend fun collapse(duration: Int = CollapsingToolbarDefaults.COLLAPSE_DURATION) { val anim = AnimationState(height.toFloat()) scroll { @@ -189,7 +189,7 @@ class CollapsingToolbarState( @Composable fun rememberCollapsingToolbarState( - initial: Int = Int.MAX_VALUE + initial: Int = CollapsingToolbarDefaults.INITIAL_HEIGHT ): CollapsingToolbarState { return remember { CollapsingToolbarState( @@ -216,6 +216,13 @@ fun CollapsingToolbar( ) } +object CollapsingToolbarDefaults { + const val INITIAL_HEIGHT = Int.MAX_VALUE + const val EDGE = 0.5f + const val EXPAND_DURATION = 200 + const val COLLAPSE_DURATION = 200 +} + private class CollapsingToolbarMeasurePolicy( private val collapsingToolbarState: CollapsingToolbarState ): MeasurePolicy { diff --git a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt index 8a06714..e47b18b 100644 --- a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt +++ b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt @@ -75,6 +75,7 @@ fun CollapsingToolbarScaffold( modifier: Modifier, state: CollapsingToolbarScaffoldState, scrollStrategy: ScrollStrategy, + snapStrategy: SnapStrategy? = null, toolbarModifier: Modifier = Modifier, toolbar: @Composable CollapsingToolbarScope.() -> Unit, body: @Composable () -> Unit @@ -82,7 +83,7 @@ fun CollapsingToolbarScaffold( val flingBehavior = ScrollableDefaults.flingBehavior() val nestedScrollConnection = remember(scrollStrategy, state) { - scrollStrategy.create(state.offsetYState, state.toolbarState, flingBehavior) + scrollStrategy.create(state.offsetYState, state.toolbarState, flingBehavior, snapStrategy) } val toolbarState = state.toolbarState diff --git a/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt b/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt index 0e0262b..7df3705 100644 --- a/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt +++ b/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt @@ -34,31 +34,35 @@ enum class ScrollStrategy { override fun create( offsetY: MutableState, toolbarState: CollapsingToolbarState, - flingBehavior: FlingBehavior + flingBehavior: FlingBehavior, + snapStrategy: SnapStrategy?, ): NestedScrollConnection = - EnterAlwaysNestedScrollConnection(offsetY, toolbarState, flingBehavior) + EnterAlwaysNestedScrollConnection(offsetY, toolbarState, flingBehavior, snapStrategy) }, EnterAlwaysCollapsed { override fun create( offsetY: MutableState, toolbarState: CollapsingToolbarState, - flingBehavior: FlingBehavior + flingBehavior: FlingBehavior, + snapStrategy: SnapStrategy?, ): NestedScrollConnection = - EnterAlwaysCollapsedNestedScrollConnection(offsetY, toolbarState, flingBehavior) + EnterAlwaysCollapsedNestedScrollConnection(offsetY, toolbarState, flingBehavior, snapStrategy) }, ExitUntilCollapsed { override fun create( offsetY: MutableState, toolbarState: CollapsingToolbarState, - flingBehavior: FlingBehavior + flingBehavior: FlingBehavior, + snapStrategy: SnapStrategy?, ): NestedScrollConnection = - ExitUntilCollapsedNestedScrollConnection(toolbarState, flingBehavior) + ExitUntilCollapsedNestedScrollConnection(toolbarState, flingBehavior, snapStrategy) }; internal abstract fun create( offsetY: MutableState, toolbarState: CollapsingToolbarState, - flingBehavior: FlingBehavior + flingBehavior: FlingBehavior, + snapStrategy: SnapStrategy?, ): NestedScrollConnection } @@ -80,7 +84,8 @@ private class ScrollDelegate( internal class EnterAlwaysNestedScrollConnection( private val offsetY: MutableState, private val toolbarState: CollapsingToolbarState, - private val flingBehavior: FlingBehavior + private val flingBehavior: FlingBehavior, + private val snapStrategy: SnapStrategy? ): NestedScrollConnection { private val scrollDelegate = ScrollDelegate(offsetY) private val tracker = RelativeVelocityTracker(CurrentTimeProviderImpl()) @@ -131,7 +136,8 @@ internal class EnterAlwaysNestedScrollConnection( internal class EnterAlwaysCollapsedNestedScrollConnection( private val offsetY: MutableState, private val toolbarState: CollapsingToolbarState, - private val flingBehavior: FlingBehavior + private val flingBehavior: FlingBehavior, + private val snapStrategy: SnapStrategy?, ): NestedScrollConnection { private val scrollDelegate = ScrollDelegate(offsetY) private val tracker = RelativeVelocityTracker(CurrentTimeProviderImpl()) @@ -192,7 +198,8 @@ internal class EnterAlwaysCollapsedNestedScrollConnection( internal class ExitUntilCollapsedNestedScrollConnection( private val toolbarState: CollapsingToolbarState, - private val flingBehavior: FlingBehavior + private val flingBehavior: FlingBehavior, + private val snapStrategy: SnapStrategy? ): NestedScrollConnection { private val tracker = RelativeVelocityTracker(CurrentTimeProviderImpl()) @@ -246,6 +253,9 @@ internal class ExitUntilCollapsedNestedScrollConnection( velocity } + // TODO: Cancel expand/collapse animation inside onPreScroll + snapStrategy?.let { toolbarState.processSnap(it) } + return available.copy(y = available.y - left) } } diff --git a/lib/src/main/java/me/onebone/toolbar/SnapStrategy.kt b/lib/src/main/java/me/onebone/toolbar/SnapStrategy.kt new file mode 100644 index 0000000..98aecd5 --- /dev/null +++ b/lib/src/main/java/me/onebone/toolbar/SnapStrategy.kt @@ -0,0 +1,21 @@ +package me.onebone.toolbar + +import androidx.annotation.FloatRange +import androidx.compose.runtime.Immutable + +@Immutable +class SnapStrategy( + @FloatRange(from = 0.0, to = 1.0) val edge: Float = CollapsingToolbarDefaults.EDGE, + val expandDuration: Int = CollapsingToolbarDefaults.EXPAND_DURATION, + val collapseDuration: Int = CollapsingToolbarDefaults.COLLAPSE_DURATION +) + +// TODO: Is there a better solution rather OptIn ExperimentalToolbarApi? +@OptIn(ExperimentalToolbarApi::class) +internal suspend fun CollapsingToolbarState.processSnap(strategy: SnapStrategy) { + if (progress > strategy.edge) { + expand(strategy.expandDuration) + } else { + collapse(strategy.collapseDuration) + } +} \ No newline at end of file diff --git a/lib/src/main/java/me/onebone/toolbar/ToolbarWithFabScaffold.kt b/lib/src/main/java/me/onebone/toolbar/ToolbarWithFabScaffold.kt index 2dd449d..426844c 100644 --- a/lib/src/main/java/me/onebone/toolbar/ToolbarWithFabScaffold.kt +++ b/lib/src/main/java/me/onebone/toolbar/ToolbarWithFabScaffold.kt @@ -12,6 +12,7 @@ fun ToolbarWithFabScaffold( modifier: Modifier, state: CollapsingToolbarScaffoldState, scrollStrategy: ScrollStrategy, + snapStrategy: SnapStrategy? = null, toolbarModifier: Modifier = Modifier, toolbar: @Composable CollapsingToolbarScope.() -> Unit, fab: @Composable () -> Unit, @@ -33,6 +34,7 @@ fun ToolbarWithFabScaffold( modifier = modifier, state = state, scrollStrategy = scrollStrategy, + snapStrategy = snapStrategy, toolbarModifier = toolbarModifier, toolbar = toolbar, body = body From 6a8db15a0d68a73948f10a5707a66cff5cc7b602 Mon Sep 17 00:00:00 2001 From: RareScrap Date: Sun, 7 Nov 2021 22:59:26 +0300 Subject: [PATCH 02/11] appbar snap implementation --- .../me/onebone/toolbar/CollapsingToolbar.kt | 43 +++++++++++++++++++ .../java/me/onebone/toolbar/ScrollStrategy.kt | 30 +++++++++++++ .../java/me/onebone/toolbar/SnapStrategy.kt | 12 +----- 3 files changed, 74 insertions(+), 11 deletions(-) diff --git a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbar.kt b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbar.kt index 1914930..d3f9a07 100644 --- a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbar.kt +++ b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbar.kt @@ -31,6 +31,7 @@ import androidx.compose.foundation.gestures.FlingBehavior import androidx.compose.foundation.gestures.ScrollScope import androidx.compose.foundation.gestures.ScrollableState import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -136,6 +137,7 @@ class CollapsingToolbarState( ) fun feedScroll(value: Float): Float = dispatchRawDelta(value) + // TODO: A strange jump in snap speed is often observed @ExperimentalToolbarApi suspend fun expand(duration: Int = CollapsingToolbarDefaults.EXPAND_DURATION) { val anim = AnimationState(height.toFloat()) @@ -149,6 +151,7 @@ class CollapsingToolbarState( } } + // TODO: A strange jump in snap speed is often observed @ExperimentalToolbarApi suspend fun collapse(duration: Int = CollapsingToolbarDefaults.COLLAPSE_DURATION) { val anim = AnimationState(height.toFloat()) @@ -162,6 +165,46 @@ class CollapsingToolbarState( } } + @ExperimentalToolbarApi + suspend fun expandOffset(snapStrategy: SnapStrategy, offsetY: MutableState) { + val anim = AnimationState(offsetY.value.toFloat()) + + anim.animateTo(0f, tween(snapStrategy.expandDuration)) { + offsetY.value = value.toInt() + } + } + + @ExperimentalToolbarApi + suspend fun collapseOffset(snapStrategy: SnapStrategy, offsetY: MutableState) { + val anim = AnimationState(offsetY.value.toFloat()) + + anim.animateTo(-minHeight.toFloat(), tween(snapStrategy.collapseDuration)) { + offsetY.value = value.toInt() + } + } + + // TODO: Is there a better solution rather OptIn ExperimentalToolbarApi? + @OptIn(ExperimentalToolbarApi::class) + internal suspend fun processSnap(strategy: SnapStrategy) { + if (progress > strategy.edge) { + expand(strategy.expandDuration) + } else { + collapse(strategy.collapseDuration) + } + } + + // TODO: Is there a better solution rather OptIn ExperimentalToolbarApi? + @OptIn(ExperimentalToolbarApi::class) + internal suspend fun processOffsetSnap(snapStrategy: SnapStrategy, offsetY: MutableState) { + val offsetProgress = + 1f - ((offsetY.value / (minHeight / 100f)) / 100f).absoluteValue + if (offsetProgress > snapStrategy.edge) { + expandOffset(snapStrategy, offsetY) + } else { + collapseOffset(snapStrategy, offsetY) + } + } + /** * @return Remaining velocity after fling */ diff --git a/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt b/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt index 7df3705..f186164 100644 --- a/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt +++ b/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt @@ -131,6 +131,23 @@ internal class EnterAlwaysNestedScrollConnection( return available.copy(y = available.y - left) } + + override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity { + // TODO: Cancel expand/collapse animation inside onPreScroll + snapStrategy?.let { + val isToolbarChangingOffset = offsetY.value != 0 + if (isToolbarChangingOffset) { + // When the toolbar is hiding, it does it through changing the offset and does not + // change its height, so we must process not the snap of the toolbar, but the + // snap of its offset. + toolbarState.processOffsetSnap(it, offsetY) + } else { + toolbarState.processSnap(it) + } + } + + return super.onPostFling(consumed, available) + } } internal class EnterAlwaysCollapsedNestedScrollConnection( @@ -192,6 +209,19 @@ internal class EnterAlwaysCollapsedNestedScrollConnection( dy } + // TODO: Cancel expand/collapse animation inside onPreScroll + snapStrategy?.let { + val isToolbarChangingOffset = offsetY.value != 0//toolbarState.progress == 0f + if (isToolbarChangingOffset) { + // When the toolbar is hiding, it does it through changing the offset and does not + // change its height, so we must process not the snap of the toolbar, but the + // snap of its offset. + toolbarState.processOffsetSnap(it, offsetY) + } else { + toolbarState.processSnap(it) + } + } + return available.copy(y = available.y - left) } } diff --git a/lib/src/main/java/me/onebone/toolbar/SnapStrategy.kt b/lib/src/main/java/me/onebone/toolbar/SnapStrategy.kt index 98aecd5..8f930e2 100644 --- a/lib/src/main/java/me/onebone/toolbar/SnapStrategy.kt +++ b/lib/src/main/java/me/onebone/toolbar/SnapStrategy.kt @@ -8,14 +8,4 @@ class SnapStrategy( @FloatRange(from = 0.0, to = 1.0) val edge: Float = CollapsingToolbarDefaults.EDGE, val expandDuration: Int = CollapsingToolbarDefaults.EXPAND_DURATION, val collapseDuration: Int = CollapsingToolbarDefaults.COLLAPSE_DURATION -) - -// TODO: Is there a better solution rather OptIn ExperimentalToolbarApi? -@OptIn(ExperimentalToolbarApi::class) -internal suspend fun CollapsingToolbarState.processSnap(strategy: SnapStrategy) { - if (progress > strategy.edge) { - expand(strategy.expandDuration) - } else { - collapse(strategy.collapseDuration) - } -} \ No newline at end of file +) \ No newline at end of file From 3bad446178d847256c92ab620115c42be07c6afb Mon Sep 17 00:00:00 2001 From: RareScrap Date: Sat, 20 Nov 2021 19:00:38 +0800 Subject: [PATCH 03/11] moved snap processing from CollapsingToolbarState to CollapsingToolbarScaffoldState + Defaults naming refactoring + TODOs added --- .../me/onebone/toolbar/AppBarContainer.kt | 12 +-- .../me/onebone/toolbar/CollapsingToolbar.kt | 84 ++----------------- .../toolbar/CollapsingToolbarScaffold.kt | 79 ++++++++++++++++- .../java/me/onebone/toolbar/ScrollStrategy.kt | 35 ++++---- .../java/me/onebone/toolbar/SnapStrategy.kt | 6 +- 5 files changed, 112 insertions(+), 104 deletions(-) diff --git a/lib/src/main/java/me/onebone/toolbar/AppBarContainer.kt b/lib/src/main/java/me/onebone/toolbar/AppBarContainer.kt index 6418d8d..b856b92 100644 --- a/lib/src/main/java/me/onebone/toolbar/AppBarContainer.kt +++ b/lib/src/main/java/me/onebone/toolbar/AppBarContainer.kt @@ -52,13 +52,13 @@ import kotlin.math.max fun AppbarContainer( modifier: Modifier = Modifier, scrollStrategy: ScrollStrategy, - collapsingToolbarState: CollapsingToolbarState, + collapsingToolbarScaffoldState: CollapsingToolbarScaffoldState, content: @Composable AppbarContainerScope.() -> Unit ) { AppBarContainer( modifier = modifier, scrollStrategy = scrollStrategy, - collapsingToolbarState = collapsingToolbarState, + collapsingToolbarScaffoldState = collapsingToolbarScaffoldState, content = content ) } @@ -75,16 +75,16 @@ fun AppBarContainer( modifier: Modifier = Modifier, scrollStrategy: ScrollStrategy, /** The state of a connected collapsing toolbar */ - collapsingToolbarState: CollapsingToolbarState, + collapsingToolbarScaffoldState: CollapsingToolbarScaffoldState, content: @Composable AppbarContainerScope.() -> Unit ) { val offsetY = remember { mutableStateOf(0) } val flingBehavior = ScrollableDefaults.flingBehavior() val snapStrategy = null - val (scope, measurePolicy) = remember(scrollStrategy, collapsingToolbarState) { - AppbarContainerScopeImpl(scrollStrategy.create(offsetY, collapsingToolbarState, flingBehavior, snapStrategy)) to - AppbarMeasurePolicy(scrollStrategy, collapsingToolbarState, offsetY) + val (scope, measurePolicy) = remember(scrollStrategy, collapsingToolbarScaffoldState) { + AppbarContainerScopeImpl(scrollStrategy.create(offsetY, collapsingToolbarScaffoldState, flingBehavior, snapStrategy)) to + AppbarMeasurePolicy(scrollStrategy, collapsingToolbarScaffoldState.toolbarState, offsetY) } Layout( diff --git a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbar.kt b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbar.kt index d3f9a07..d7ec737 100644 --- a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbar.kt +++ b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbar.kt @@ -23,15 +23,11 @@ package me.onebone.toolbar import androidx.annotation.FloatRange -import androidx.compose.animation.core.AnimationState -import androidx.compose.animation.core.animateTo -import androidx.compose.animation.core.tween import androidx.compose.foundation.MutatePriority import androidx.compose.foundation.gestures.FlingBehavior import androidx.compose.foundation.gestures.ScrollScope import androidx.compose.foundation.gestures.ScrollableState import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -58,7 +54,7 @@ import kotlin.math.roundToInt @Stable class CollapsingToolbarState( - initial: Int = CollapsingToolbarDefaults.INITIAL_HEIGHT + initial: Int = CollapsingToolbarDefaults.InitialHeight ): ScrollableState { /** * [height] indicates current height of the toolbar. @@ -137,74 +133,6 @@ class CollapsingToolbarState( ) fun feedScroll(value: Float): Float = dispatchRawDelta(value) - // TODO: A strange jump in snap speed is often observed - @ExperimentalToolbarApi - suspend fun expand(duration: Int = CollapsingToolbarDefaults.EXPAND_DURATION) { - val anim = AnimationState(height.toFloat()) - - scroll { - var prev = anim.value - anim.animateTo(maxHeight.toFloat(), tween(duration)) { - scrollBy(value - prev) - prev = value - } - } - } - - // TODO: A strange jump in snap speed is often observed - @ExperimentalToolbarApi - suspend fun collapse(duration: Int = CollapsingToolbarDefaults.COLLAPSE_DURATION) { - val anim = AnimationState(height.toFloat()) - - scroll { - var prev = anim.value - anim.animateTo(minHeight.toFloat(), tween(duration)) { - scrollBy(value - prev) - prev = value - } - } - } - - @ExperimentalToolbarApi - suspend fun expandOffset(snapStrategy: SnapStrategy, offsetY: MutableState) { - val anim = AnimationState(offsetY.value.toFloat()) - - anim.animateTo(0f, tween(snapStrategy.expandDuration)) { - offsetY.value = value.toInt() - } - } - - @ExperimentalToolbarApi - suspend fun collapseOffset(snapStrategy: SnapStrategy, offsetY: MutableState) { - val anim = AnimationState(offsetY.value.toFloat()) - - anim.animateTo(-minHeight.toFloat(), tween(snapStrategy.collapseDuration)) { - offsetY.value = value.toInt() - } - } - - // TODO: Is there a better solution rather OptIn ExperimentalToolbarApi? - @OptIn(ExperimentalToolbarApi::class) - internal suspend fun processSnap(strategy: SnapStrategy) { - if (progress > strategy.edge) { - expand(strategy.expandDuration) - } else { - collapse(strategy.collapseDuration) - } - } - - // TODO: Is there a better solution rather OptIn ExperimentalToolbarApi? - @OptIn(ExperimentalToolbarApi::class) - internal suspend fun processOffsetSnap(snapStrategy: SnapStrategy, offsetY: MutableState) { - val offsetProgress = - 1f - ((offsetY.value / (minHeight / 100f)) / 100f).absoluteValue - if (offsetProgress > snapStrategy.edge) { - expandOffset(snapStrategy, offsetY) - } else { - collapseOffset(snapStrategy, offsetY) - } - } - /** * @return Remaining velocity after fling */ @@ -232,7 +160,7 @@ class CollapsingToolbarState( @Composable fun rememberCollapsingToolbarState( - initial: Int = CollapsingToolbarDefaults.INITIAL_HEIGHT + initial: Int = CollapsingToolbarDefaults.InitialHeight ): CollapsingToolbarState { return remember { CollapsingToolbarState( @@ -260,10 +188,10 @@ fun CollapsingToolbar( } object CollapsingToolbarDefaults { - const val INITIAL_HEIGHT = Int.MAX_VALUE - const val EDGE = 0.5f - const val EXPAND_DURATION = 200 - const val COLLAPSE_DURATION = 200 + const val InitialHeight = Int.MAX_VALUE + const val Edge = 0.5f + const val ExpandDuration = 200 + const val CollapseDuration = 200 } private class CollapsingToolbarMeasurePolicy( diff --git a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt index e47b18b..6927561 100644 --- a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt +++ b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt @@ -23,6 +23,9 @@ package me.onebone.toolbar import android.os.Bundle +import androidx.compose.animation.core.AnimationState +import androidx.compose.animation.core.animateTo +import androidx.compose.animation.core.tween import androidx.compose.foundation.gestures.ScrollableDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable @@ -34,6 +37,7 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.layout.SubcomposeLayout +import kotlin.math.absoluteValue import kotlin.math.max @Stable @@ -45,6 +49,78 @@ class CollapsingToolbarScaffoldState( get() = offsetYState.value internal val offsetYState = mutableStateOf(initialOffsetY) + + // TODO: Maybe should move toolbar expand/collapse methods to CollapsingToolbarState + // but offset expand/collapse leave in CollapsingToolbarScaffoldState? + + // TODO: A strange jump in snap speed is often observed + @ExperimentalToolbarApi + suspend fun expand(duration: Int = CollapsingToolbarDefaults.ExpandDuration) { + val anim = AnimationState(toolbarState.height.toFloat()) + + toolbarState.scroll { + var prev = anim.value + anim.animateTo(toolbarState.maxHeight.toFloat(), tween(duration)) { + scrollBy(value - prev) + prev = value + } + } + } + + // TODO: A strange jump in snap speed is often observed + @ExperimentalToolbarApi + suspend fun collapse(duration: Int = CollapsingToolbarDefaults.CollapseDuration) { + val anim = AnimationState(toolbarState.height.toFloat()) + + toolbarState.scroll { + var prev = anim.value + anim.animateTo(toolbarState.minHeight.toFloat(), tween(duration)) { + scrollBy(value - prev) + prev = value + } + } + } + + @ExperimentalToolbarApi + suspend fun expandOffset(snapStrategy: SnapStrategy) { + val anim = AnimationState(offsetYState.value.toFloat()) + + anim.animateTo(0f, tween(snapStrategy.expandDuration)) { + offsetYState.value = value.toInt() + } + } + + @ExperimentalToolbarApi + suspend fun collapseOffset(snapStrategy: SnapStrategy) { + val anim = AnimationState(offsetYState.value.toFloat()) + + anim.animateTo(-toolbarState.minHeight.toFloat(), tween(snapStrategy.collapseDuration)) { + offsetYState.value = value.toInt() + } + } + + // TODO: Is there a better solution rather OptIn ExperimentalToolbarApi? + @OptIn(ExperimentalToolbarApi::class) + internal suspend fun processSnap(strategy: SnapStrategy) { + if (toolbarState.progress > strategy.edge) { + expand(strategy.expandDuration) + } else { + collapse(strategy.collapseDuration) + } + } + + // TODO: Is there a better solution rather OptIn ExperimentalToolbarApi? + @OptIn(ExperimentalToolbarApi::class) + internal suspend fun processOffsetSnap(snapStrategy: SnapStrategy) { + // TODO: Refactor ugly math + val offsetProgress = + 1f - ((offsetYState.value / (toolbarState.minHeight / 100f)) / 100f).absoluteValue + if (offsetProgress > snapStrategy.edge) { + expandOffset(snapStrategy) + } else { + collapseOffset(snapStrategy) + } + } } private class CollapsingToolbarScaffoldStateSaver: Saver { @@ -83,7 +159,8 @@ fun CollapsingToolbarScaffold( val flingBehavior = ScrollableDefaults.flingBehavior() val nestedScrollConnection = remember(scrollStrategy, state) { - scrollStrategy.create(state.offsetYState, state.toolbarState, flingBehavior, snapStrategy) + // TODO by RareScrap: Should we make offsetYState public and pass just state? + scrollStrategy.create(state.offsetYState, state, flingBehavior, snapStrategy) } val toolbarState = state.toolbarState diff --git a/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt b/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt index f186164..ed9b38d 100644 --- a/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt +++ b/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt @@ -33,34 +33,34 @@ enum class ScrollStrategy { EnterAlways { override fun create( offsetY: MutableState, - toolbarState: CollapsingToolbarState, + scaffoldState: CollapsingToolbarScaffoldState, flingBehavior: FlingBehavior, snapStrategy: SnapStrategy?, ): NestedScrollConnection = - EnterAlwaysNestedScrollConnection(offsetY, toolbarState, flingBehavior, snapStrategy) + EnterAlwaysNestedScrollConnection(offsetY, scaffoldState, flingBehavior, snapStrategy) }, EnterAlwaysCollapsed { override fun create( offsetY: MutableState, - toolbarState: CollapsingToolbarState, + scaffoldState: CollapsingToolbarScaffoldState, flingBehavior: FlingBehavior, snapStrategy: SnapStrategy?, ): NestedScrollConnection = - EnterAlwaysCollapsedNestedScrollConnection(offsetY, toolbarState, flingBehavior, snapStrategy) + EnterAlwaysCollapsedNestedScrollConnection(offsetY, scaffoldState, flingBehavior, snapStrategy) }, ExitUntilCollapsed { override fun create( offsetY: MutableState, - toolbarState: CollapsingToolbarState, + scaffoldState: CollapsingToolbarScaffoldState, flingBehavior: FlingBehavior, snapStrategy: SnapStrategy?, ): NestedScrollConnection = - ExitUntilCollapsedNestedScrollConnection(toolbarState, flingBehavior, snapStrategy) + ExitUntilCollapsedNestedScrollConnection(scaffoldState, flingBehavior, snapStrategy) }; internal abstract fun create( offsetY: MutableState, - toolbarState: CollapsingToolbarState, + scaffoldState: CollapsingToolbarScaffoldState, flingBehavior: FlingBehavior, snapStrategy: SnapStrategy?, ): NestedScrollConnection @@ -83,12 +83,13 @@ private class ScrollDelegate( internal class EnterAlwaysNestedScrollConnection( private val offsetY: MutableState, - private val toolbarState: CollapsingToolbarState, + private val scaffoldState: CollapsingToolbarScaffoldState, private val flingBehavior: FlingBehavior, private val snapStrategy: SnapStrategy? ): NestedScrollConnection { private val scrollDelegate = ScrollDelegate(offsetY) private val tracker = RelativeVelocityTracker(CurrentTimeProviderImpl()) + private val toolbarState = scaffoldState.toolbarState override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { val dy = available.y @@ -140,9 +141,9 @@ internal class EnterAlwaysNestedScrollConnection( // When the toolbar is hiding, it does it through changing the offset and does not // change its height, so we must process not the snap of the toolbar, but the // snap of its offset. - toolbarState.processOffsetSnap(it, offsetY) + scaffoldState.processOffsetSnap(it) } else { - toolbarState.processSnap(it) + scaffoldState.processSnap(it) } } @@ -152,12 +153,13 @@ internal class EnterAlwaysNestedScrollConnection( internal class EnterAlwaysCollapsedNestedScrollConnection( private val offsetY: MutableState, - private val toolbarState: CollapsingToolbarState, + private val scaffoldState: CollapsingToolbarScaffoldState, private val flingBehavior: FlingBehavior, private val snapStrategy: SnapStrategy?, ): NestedScrollConnection { private val scrollDelegate = ScrollDelegate(offsetY) private val tracker = RelativeVelocityTracker(CurrentTimeProviderImpl()) + private val toolbarState = scaffoldState.toolbarState override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { val dy = available.y @@ -211,14 +213,14 @@ internal class EnterAlwaysCollapsedNestedScrollConnection( // TODO: Cancel expand/collapse animation inside onPreScroll snapStrategy?.let { - val isToolbarChangingOffset = offsetY.value != 0//toolbarState.progress == 0f + val isToolbarChangingOffset = offsetY.value != 0 if (isToolbarChangingOffset) { // When the toolbar is hiding, it does it through changing the offset and does not // change its height, so we must process not the snap of the toolbar, but the // snap of its offset. - toolbarState.processOffsetSnap(it, offsetY) + scaffoldState.processOffsetSnap(it) } else { - toolbarState.processSnap(it) + scaffoldState.processSnap(it) } } @@ -227,11 +229,12 @@ internal class EnterAlwaysCollapsedNestedScrollConnection( } internal class ExitUntilCollapsedNestedScrollConnection( - private val toolbarState: CollapsingToolbarState, + private val scaffoldState: CollapsingToolbarScaffoldState, private val flingBehavior: FlingBehavior, private val snapStrategy: SnapStrategy? ): NestedScrollConnection { private val tracker = RelativeVelocityTracker(CurrentTimeProviderImpl()) + private val toolbarState = scaffoldState.toolbarState override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { val dy = available.y @@ -284,7 +287,7 @@ internal class ExitUntilCollapsedNestedScrollConnection( } // TODO: Cancel expand/collapse animation inside onPreScroll - snapStrategy?.let { toolbarState.processSnap(it) } + snapStrategy?.let { scaffoldState.processSnap(it) } return available.copy(y = available.y - left) } diff --git a/lib/src/main/java/me/onebone/toolbar/SnapStrategy.kt b/lib/src/main/java/me/onebone/toolbar/SnapStrategy.kt index 8f930e2..60d0477 100644 --- a/lib/src/main/java/me/onebone/toolbar/SnapStrategy.kt +++ b/lib/src/main/java/me/onebone/toolbar/SnapStrategy.kt @@ -5,7 +5,7 @@ import androidx.compose.runtime.Immutable @Immutable class SnapStrategy( - @FloatRange(from = 0.0, to = 1.0) val edge: Float = CollapsingToolbarDefaults.EDGE, - val expandDuration: Int = CollapsingToolbarDefaults.EXPAND_DURATION, - val collapseDuration: Int = CollapsingToolbarDefaults.COLLAPSE_DURATION + @FloatRange(from = 0.0, to = 1.0) val edge: Float = CollapsingToolbarDefaults.Edge, + val expandDuration: Int = CollapsingToolbarDefaults.ExpandDuration, + val collapseDuration: Int = CollapsingToolbarDefaults.CollapseDuration ) \ No newline at end of file From 68f16b8f98f935e69852fed80112bd76548ab248 Mon Sep 17 00:00:00 2001 From: RareScrap Date: Thu, 23 Dec 2021 22:03:08 +0800 Subject: [PATCH 04/11] added end line --- lib/src/main/java/me/onebone/toolbar/SnapStrategy.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/main/java/me/onebone/toolbar/SnapStrategy.kt b/lib/src/main/java/me/onebone/toolbar/SnapStrategy.kt index 60d0477..a2202d1 100644 --- a/lib/src/main/java/me/onebone/toolbar/SnapStrategy.kt +++ b/lib/src/main/java/me/onebone/toolbar/SnapStrategy.kt @@ -8,4 +8,4 @@ class SnapStrategy( @FloatRange(from = 0.0, to = 1.0) val edge: Float = CollapsingToolbarDefaults.Edge, val expandDuration: Int = CollapsingToolbarDefaults.ExpandDuration, val collapseDuration: Int = CollapsingToolbarDefaults.CollapseDuration -) \ No newline at end of file +) From 14acae5aa75cdfbbfae4506fa0fc162581a3e0f1 Mon Sep 17 00:00:00 2001 From: RareScrap Date: Thu, 23 Dec 2021 22:04:41 +0800 Subject: [PATCH 05/11] moved toolbar expand/collapse methods to CollapsingToolbarState --- .../me/onebone/toolbar/CollapsingToolbar.kt | 46 +++++++++++++------ .../toolbar/CollapsingToolbarScaffold.kt | 35 +------------- 2 files changed, 35 insertions(+), 46 deletions(-) diff --git a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbar.kt b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbar.kt index d7ec737..8407358 100644 --- a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbar.kt +++ b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbar.kt @@ -23,26 +23,18 @@ package me.onebone.toolbar import androidx.annotation.FloatRange +import androidx.compose.animation.core.AnimationState +import androidx.compose.animation.core.animateTo +import androidx.compose.animation.core.tween import androidx.compose.foundation.MutatePriority import androidx.compose.foundation.gestures.FlingBehavior import androidx.compose.foundation.gestures.ScrollScope import androidx.compose.foundation.gestures.ScrollableState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.Stable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clipToBounds -import androidx.compose.ui.layout.Layout -import androidx.compose.ui.layout.Measurable -import androidx.compose.ui.layout.MeasurePolicy -import androidx.compose.ui.layout.MeasureResult -import androidx.compose.ui.layout.MeasureScope -import androidx.compose.ui.layout.ParentDataModifier -import androidx.compose.ui.layout.Placeable +import androidx.compose.ui.layout.* import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.IntSize @@ -147,6 +139,34 @@ class CollapsingToolbarState( return left } + // TODO: A strange jump in snap speed is often observed + @ExperimentalToolbarApi + suspend fun expand(duration: Int = CollapsingToolbarDefaults.ExpandDuration) { + val anim = AnimationState(height.toFloat()) + + scroll { + var prev = anim.value + anim.animateTo(maxHeight.toFloat(), tween(duration)) { + scrollBy(value - prev) + prev = value + } + } + } + + // TODO: A strange jump in snap speed is often observed + @ExperimentalToolbarApi + suspend fun collapse(duration: Int = CollapsingToolbarDefaults.CollapseDuration) { + val anim = AnimationState(height.toFloat()) + + scroll { + var prev = anim.value + anim.animateTo(minHeight.toFloat(), tween(duration)) { + scrollBy(value - prev) + prev = value + } + } + } + override val isScrollInProgress: Boolean get() = scrollableState.isScrollInProgress diff --git a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt index 6927561..2cb450d 100644 --- a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt +++ b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt @@ -50,37 +50,6 @@ class CollapsingToolbarScaffoldState( internal val offsetYState = mutableStateOf(initialOffsetY) - // TODO: Maybe should move toolbar expand/collapse methods to CollapsingToolbarState - // but offset expand/collapse leave in CollapsingToolbarScaffoldState? - - // TODO: A strange jump in snap speed is often observed - @ExperimentalToolbarApi - suspend fun expand(duration: Int = CollapsingToolbarDefaults.ExpandDuration) { - val anim = AnimationState(toolbarState.height.toFloat()) - - toolbarState.scroll { - var prev = anim.value - anim.animateTo(toolbarState.maxHeight.toFloat(), tween(duration)) { - scrollBy(value - prev) - prev = value - } - } - } - - // TODO: A strange jump in snap speed is often observed - @ExperimentalToolbarApi - suspend fun collapse(duration: Int = CollapsingToolbarDefaults.CollapseDuration) { - val anim = AnimationState(toolbarState.height.toFloat()) - - toolbarState.scroll { - var prev = anim.value - anim.animateTo(toolbarState.minHeight.toFloat(), tween(duration)) { - scrollBy(value - prev) - prev = value - } - } - } - @ExperimentalToolbarApi suspend fun expandOffset(snapStrategy: SnapStrategy) { val anim = AnimationState(offsetYState.value.toFloat()) @@ -103,9 +72,9 @@ class CollapsingToolbarScaffoldState( @OptIn(ExperimentalToolbarApi::class) internal suspend fun processSnap(strategy: SnapStrategy) { if (toolbarState.progress > strategy.edge) { - expand(strategy.expandDuration) + toolbarState.expand(strategy.expandDuration) } else { - collapse(strategy.collapseDuration) + toolbarState.collapse(strategy.collapseDuration) } } From ef7cbdf1cd1c653354171a96caa840eae005e224 Mon Sep 17 00:00:00 2001 From: RareScrap Date: Thu, 23 Dec 2021 22:47:40 +0800 Subject: [PATCH 06/11] removed redundant offsetY passing --- .../me/onebone/toolbar/AppBarContainer.kt | 24 ++++++------------ .../toolbar/CollapsingToolbarScaffold.kt | 9 +++---- .../java/me/onebone/toolbar/ScrollStrategy.kt | 25 ++++++++----------- 3 files changed, 22 insertions(+), 36 deletions(-) diff --git a/lib/src/main/java/me/onebone/toolbar/AppBarContainer.kt b/lib/src/main/java/me/onebone/toolbar/AppBarContainer.kt index b856b92..bba413f 100644 --- a/lib/src/main/java/me/onebone/toolbar/AppBarContainer.kt +++ b/lib/src/main/java/me/onebone/toolbar/AppBarContainer.kt @@ -24,19 +24,11 @@ package me.onebone.toolbar import androidx.compose.foundation.gestures.ScrollableDefaults import androidx.compose.runtime.Composable -import androidx.compose.runtime.State -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.nestedScroll -import androidx.compose.ui.layout.Layout -import androidx.compose.ui.layout.Measurable -import androidx.compose.ui.layout.MeasurePolicy -import androidx.compose.ui.layout.MeasureResult -import androidx.compose.ui.layout.MeasureScope -import androidx.compose.ui.layout.ParentDataModifier -import androidx.compose.ui.layout.Placeable +import androidx.compose.ui.layout.* import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.Density import kotlin.math.max @@ -78,13 +70,12 @@ fun AppBarContainer( collapsingToolbarScaffoldState: CollapsingToolbarScaffoldState, content: @Composable AppbarContainerScope.() -> Unit ) { - val offsetY = remember { mutableStateOf(0) } val flingBehavior = ScrollableDefaults.flingBehavior() val snapStrategy = null val (scope, measurePolicy) = remember(scrollStrategy, collapsingToolbarScaffoldState) { - AppbarContainerScopeImpl(scrollStrategy.create(offsetY, collapsingToolbarScaffoldState, flingBehavior, snapStrategy)) to - AppbarMeasurePolicy(scrollStrategy, collapsingToolbarScaffoldState.toolbarState, offsetY) + AppbarContainerScopeImpl(scrollStrategy.create(collapsingToolbarScaffoldState, flingBehavior, snapStrategy)) to + AppbarMeasurePolicy(scrollStrategy, collapsingToolbarScaffoldState) } Layout( @@ -118,8 +109,7 @@ private object AppBarBodyMarker private class AppbarMeasurePolicy( private val scrollStrategy: ScrollStrategy, - private val toolbarState: CollapsingToolbarState, - private val offsetY: State + private val collapsingToolbarScaffoldState: CollapsingToolbarScaffoldState ): MeasurePolicy { override fun MeasureScope.measure( measurables: List, @@ -151,6 +141,7 @@ private class AppbarMeasurePolicy( } } + val toolbarState = collapsingToolbarScaffoldState.toolbarState val placeables = nonToolbars.map { measurable -> val childConstraints = if(scrollStrategy == ScrollStrategy.ExitUntilCollapsed) { constraints.copy( @@ -175,16 +166,17 @@ private class AppbarMeasurePolicy( height += (toolbarPlaceable?.height ?: 0) + val offsetY = collapsingToolbarScaffoldState.offsetY return layout( width.coerceIn(constraints.minWidth, constraints.maxWidth), height.coerceIn(constraints.minHeight, constraints.maxHeight) ) { - toolbarPlaceable?.place(x = 0, y = offsetY.value) + toolbarPlaceable?.place(x = 0, y = offsetY) placeables.forEach { placeable -> placeable.place( x = 0, - y = offsetY.value + (toolbarPlaceable?.height ?: 0) + y = offsetY + (toolbarPlaceable?.height ?: 0) ) } } diff --git a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt index 2cb450d..691ae17 100644 --- a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt +++ b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt @@ -52,7 +52,7 @@ class CollapsingToolbarScaffoldState( @ExperimentalToolbarApi suspend fun expandOffset(snapStrategy: SnapStrategy) { - val anim = AnimationState(offsetYState.value.toFloat()) + val anim = AnimationState(offsetY.toFloat()) anim.animateTo(0f, tween(snapStrategy.expandDuration)) { offsetYState.value = value.toInt() @@ -61,7 +61,7 @@ class CollapsingToolbarScaffoldState( @ExperimentalToolbarApi suspend fun collapseOffset(snapStrategy: SnapStrategy) { - val anim = AnimationState(offsetYState.value.toFloat()) + val anim = AnimationState(offsetY.toFloat()) anim.animateTo(-toolbarState.minHeight.toFloat(), tween(snapStrategy.collapseDuration)) { offsetYState.value = value.toInt() @@ -83,7 +83,7 @@ class CollapsingToolbarScaffoldState( internal suspend fun processOffsetSnap(snapStrategy: SnapStrategy) { // TODO: Refactor ugly math val offsetProgress = - 1f - ((offsetYState.value / (toolbarState.minHeight / 100f)) / 100f).absoluteValue + 1f - ((offsetY / (toolbarState.minHeight / 100f)) / 100f).absoluteValue if (offsetProgress > snapStrategy.edge) { expandOffset(snapStrategy) } else { @@ -128,8 +128,7 @@ fun CollapsingToolbarScaffold( val flingBehavior = ScrollableDefaults.flingBehavior() val nestedScrollConnection = remember(scrollStrategy, state) { - // TODO by RareScrap: Should we make offsetYState public and pass just state? - scrollStrategy.create(state.offsetYState, state, flingBehavior, snapStrategy) + scrollStrategy.create(state, flingBehavior, snapStrategy) } val toolbarState = state.toolbarState diff --git a/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt b/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt index ed9b38d..e978a4e 100644 --- a/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt +++ b/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt @@ -32,25 +32,22 @@ import androidx.compose.ui.unit.Velocity enum class ScrollStrategy { EnterAlways { override fun create( - offsetY: MutableState, scaffoldState: CollapsingToolbarScaffoldState, flingBehavior: FlingBehavior, snapStrategy: SnapStrategy?, ): NestedScrollConnection = - EnterAlwaysNestedScrollConnection(offsetY, scaffoldState, flingBehavior, snapStrategy) + EnterAlwaysNestedScrollConnection(scaffoldState, flingBehavior, snapStrategy) }, EnterAlwaysCollapsed { override fun create( - offsetY: MutableState, scaffoldState: CollapsingToolbarScaffoldState, flingBehavior: FlingBehavior, snapStrategy: SnapStrategy?, ): NestedScrollConnection = - EnterAlwaysCollapsedNestedScrollConnection(offsetY, scaffoldState, flingBehavior, snapStrategy) + EnterAlwaysCollapsedNestedScrollConnection(scaffoldState, flingBehavior, snapStrategy) }, ExitUntilCollapsed { override fun create( - offsetY: MutableState, scaffoldState: CollapsingToolbarScaffoldState, flingBehavior: FlingBehavior, snapStrategy: SnapStrategy?, @@ -59,7 +56,6 @@ enum class ScrollStrategy { }; internal abstract fun create( - offsetY: MutableState, scaffoldState: CollapsingToolbarScaffoldState, flingBehavior: FlingBehavior, snapStrategy: SnapStrategy?, @@ -82,12 +78,11 @@ private class ScrollDelegate( } internal class EnterAlwaysNestedScrollConnection( - private val offsetY: MutableState, private val scaffoldState: CollapsingToolbarScaffoldState, private val flingBehavior: FlingBehavior, private val snapStrategy: SnapStrategy? ): NestedScrollConnection { - private val scrollDelegate = ScrollDelegate(offsetY) + private val scrollDelegate = ScrollDelegate(scaffoldState.offsetYState) private val tracker = RelativeVelocityTracker(CurrentTimeProviderImpl()) private val toolbarState = scaffoldState.toolbarState @@ -96,7 +91,7 @@ internal class EnterAlwaysNestedScrollConnection( tracker.delta(dy) val toolbar = toolbarState.height.toFloat() - val offset = offsetY.value.toFloat() + val offset = scaffoldState.offsetY.toFloat() // -toolbarHeight <= offsetY + dy <= 0 val consume = if(dy < 0) { @@ -136,7 +131,7 @@ internal class EnterAlwaysNestedScrollConnection( override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity { // TODO: Cancel expand/collapse animation inside onPreScroll snapStrategy?.let { - val isToolbarChangingOffset = offsetY.value != 0 + val isToolbarChangingOffset = scaffoldState.offsetY != 0 if (isToolbarChangingOffset) { // When the toolbar is hiding, it does it through changing the offset and does not // change its height, so we must process not the snap of the toolbar, but the @@ -152,12 +147,11 @@ internal class EnterAlwaysNestedScrollConnection( } internal class EnterAlwaysCollapsedNestedScrollConnection( - private val offsetY: MutableState, private val scaffoldState: CollapsingToolbarScaffoldState, private val flingBehavior: FlingBehavior, private val snapStrategy: SnapStrategy?, ): NestedScrollConnection { - private val scrollDelegate = ScrollDelegate(offsetY) + private val scrollDelegate = ScrollDelegate(scaffoldState.offsetYState) private val tracker = RelativeVelocityTracker(CurrentTimeProviderImpl()) private val toolbarState = scaffoldState.toolbarState @@ -166,13 +160,14 @@ internal class EnterAlwaysCollapsedNestedScrollConnection( tracker.delta(dy) val consumed = if(dy > 0) { // expanding: offset -> body -> toolbar - val offsetConsumption = dy.coerceAtMost(-offsetY.value.toFloat()) + val offsetConsumption = dy.coerceAtMost(-scaffoldState.offsetY.toFloat()) scrollDelegate.doScroll(offsetConsumption) offsetConsumption }else{ // collapsing: toolbar -> offset -> body val toolbarConsumption = toolbarState.dispatchRawDelta(dy) - val offsetConsumption = (dy - toolbarConsumption).coerceAtLeast(-toolbarState.height.toFloat() - offsetY.value) + val offsetConsumption = (dy - toolbarConsumption) + .coerceAtLeast(-toolbarState.height.toFloat() - scaffoldState.offsetY) scrollDelegate.doScroll(offsetConsumption) @@ -213,7 +208,7 @@ internal class EnterAlwaysCollapsedNestedScrollConnection( // TODO: Cancel expand/collapse animation inside onPreScroll snapStrategy?.let { - val isToolbarChangingOffset = offsetY.value != 0 + val isToolbarChangingOffset = scaffoldState.offsetY != 0 if (isToolbarChangingOffset) { // When the toolbar is hiding, it does it through changing the offset and does not // change its height, so we must process not the snap of the toolbar, but the From f2842b7517d413a0667c7d39ad4aef67c3be7d8a Mon Sep 17 00:00:00 2001 From: RareScrap Date: Thu, 23 Dec 2021 23:06:20 +0800 Subject: [PATCH 07/11] processSnap and processOffsetSnap moved into extensions --- .../toolbar/CollapsingToolbarScaffold.kt | 24 ------------- .../java/me/onebone/toolbar/ScrollStrategy.kt | 34 ++++++++++++++++--- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt index 691ae17..88e28fd 100644 --- a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt +++ b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt @@ -37,7 +37,6 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.layout.SubcomposeLayout -import kotlin.math.absoluteValue import kotlin.math.max @Stable @@ -67,29 +66,6 @@ class CollapsingToolbarScaffoldState( offsetYState.value = value.toInt() } } - - // TODO: Is there a better solution rather OptIn ExperimentalToolbarApi? - @OptIn(ExperimentalToolbarApi::class) - internal suspend fun processSnap(strategy: SnapStrategy) { - if (toolbarState.progress > strategy.edge) { - toolbarState.expand(strategy.expandDuration) - } else { - toolbarState.collapse(strategy.collapseDuration) - } - } - - // TODO: Is there a better solution rather OptIn ExperimentalToolbarApi? - @OptIn(ExperimentalToolbarApi::class) - internal suspend fun processOffsetSnap(snapStrategy: SnapStrategy) { - // TODO: Refactor ugly math - val offsetProgress = - 1f - ((offsetY / (toolbarState.minHeight / 100f)) / 100f).absoluteValue - if (offsetProgress > snapStrategy.edge) { - expandOffset(snapStrategy) - } else { - collapseOffset(snapStrategy) - } - } } private class CollapsingToolbarScaffoldStateSaver: Saver { diff --git a/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt b/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt index e978a4e..69ccd23 100644 --- a/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt +++ b/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt @@ -28,6 +28,7 @@ import androidx.compose.ui.geometry.Offset import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.unit.Velocity +import kotlin.math.absoluteValue enum class ScrollStrategy { EnterAlways { @@ -136,9 +137,9 @@ internal class EnterAlwaysNestedScrollConnection( // When the toolbar is hiding, it does it through changing the offset and does not // change its height, so we must process not the snap of the toolbar, but the // snap of its offset. - scaffoldState.processOffsetSnap(it) + scaffoldState.performOffsetSnap(it) } else { - scaffoldState.processSnap(it) + toolbarState.performSnap(it) } } @@ -213,9 +214,9 @@ internal class EnterAlwaysCollapsedNestedScrollConnection( // When the toolbar is hiding, it does it through changing the offset and does not // change its height, so we must process not the snap of the toolbar, but the // snap of its offset. - scaffoldState.processOffsetSnap(it) + scaffoldState.performOffsetSnap(it) } else { - scaffoldState.processSnap(it) + toolbarState.performSnap(it) } } @@ -282,8 +283,31 @@ internal class ExitUntilCollapsedNestedScrollConnection( } // TODO: Cancel expand/collapse animation inside onPreScroll - snapStrategy?.let { scaffoldState.processSnap(it) } + snapStrategy?.let { scaffoldState.toolbarState.performSnap(it) } return available.copy(y = available.y - left) } } + +// TODO: Is there a better solution rather OptIn ExperimentalToolbarApi? +@OptIn(ExperimentalToolbarApi::class) +private suspend fun CollapsingToolbarState.performSnap(strategy: SnapStrategy) { + if (progress > strategy.edge) { + expand(strategy.expandDuration) + } else { + collapse(strategy.collapseDuration) + } +} + +// TODO: Is there a better solution rather OptIn ExperimentalToolbarApi? +@OptIn(ExperimentalToolbarApi::class) +private suspend fun CollapsingToolbarScaffoldState.performOffsetSnap(snapStrategy: SnapStrategy) { + // TODO: Refactor ugly math + val offsetProgress = + 1f - ((offsetY / (toolbarState.minHeight / 100f)) / 100f).absoluteValue + if (offsetProgress > snapStrategy.edge) { + expandOffset(snapStrategy) + } else { + collapseOffset(snapStrategy) + } +} From 5ba771d5b2d5bf7d42adfa09ce47c4a2c087cf76 Mon Sep 17 00:00:00 2001 From: RareScrap Date: Thu, 23 Dec 2021 23:23:51 +0800 Subject: [PATCH 08/11] refactored argument of collapseOffset and expandOffset --- .../java/me/onebone/toolbar/CollapsingToolbarScaffold.kt | 8 ++++---- lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt index 88e28fd..82f7846 100644 --- a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt +++ b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt @@ -50,19 +50,19 @@ class CollapsingToolbarScaffoldState( internal val offsetYState = mutableStateOf(initialOffsetY) @ExperimentalToolbarApi - suspend fun expandOffset(snapStrategy: SnapStrategy) { + suspend fun expandOffset(duration: Int = CollapsingToolbarDefaults.ExpandDuration) { val anim = AnimationState(offsetY.toFloat()) - anim.animateTo(0f, tween(snapStrategy.expandDuration)) { + anim.animateTo(0f, tween(duration)) { offsetYState.value = value.toInt() } } @ExperimentalToolbarApi - suspend fun collapseOffset(snapStrategy: SnapStrategy) { + suspend fun collapseOffset(duration: Int = CollapsingToolbarDefaults.CollapseDuration) { val anim = AnimationState(offsetY.toFloat()) - anim.animateTo(-toolbarState.minHeight.toFloat(), tween(snapStrategy.collapseDuration)) { + anim.animateTo(-toolbarState.minHeight.toFloat(), tween(duration)) { offsetYState.value = value.toInt() } } diff --git a/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt b/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt index 69ccd23..5113162 100644 --- a/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt +++ b/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt @@ -306,8 +306,8 @@ private suspend fun CollapsingToolbarScaffoldState.performOffsetSnap(snapStrateg val offsetProgress = 1f - ((offsetY / (toolbarState.minHeight / 100f)) / 100f).absoluteValue if (offsetProgress > snapStrategy.edge) { - expandOffset(snapStrategy) + expandOffset(snapStrategy.expandDuration) } else { - collapseOffset(snapStrategy) + collapseOffset(snapStrategy.collapseDuration) } } From 241ccabb027be07c21d2a320775792f8e9b2b42f Mon Sep 17 00:00:00 2001 From: RareScrap Date: Thu, 23 Dec 2021 23:31:52 +0800 Subject: [PATCH 09/11] refactored ugly math --- lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt b/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt index 5113162..10ac24b 100644 --- a/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt +++ b/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt @@ -302,9 +302,9 @@ private suspend fun CollapsingToolbarState.performSnap(strategy: SnapStrategy) { // TODO: Is there a better solution rather OptIn ExperimentalToolbarApi? @OptIn(ExperimentalToolbarApi::class) private suspend fun CollapsingToolbarScaffoldState.performOffsetSnap(snapStrategy: SnapStrategy) { - // TODO: Refactor ugly math - val offsetProgress = - 1f - ((offsetY / (toolbarState.minHeight / 100f)) / 100f).absoluteValue + if (toolbarState.minHeight == 0) return + + val offsetProgress = 1f - (offsetY / toolbarState.minHeight).absoluteValue if (offsetProgress > snapStrategy.edge) { expandOffset(snapStrategy.expandDuration) } else { From a9472a616521c4d7a8d0ec352b9be18b9d1b324e Mon Sep 17 00:00:00 2001 From: RareScrap Date: Fri, 24 Dec 2021 15:47:15 +0800 Subject: [PATCH 10/11] renamed SnapStrategy to SnapConfig --- .../me/onebone/toolbar/ParallaxActivity.kt | 8 +--- .../toolbar/CollapsingToolbarScaffold.kt | 4 +- .../java/me/onebone/toolbar/ScrollStrategy.kt | 42 +++++++++---------- .../{SnapStrategy.kt => SnapConfig.kt} | 2 +- .../onebone/toolbar/ToolbarWithFabScaffold.kt | 4 +- 5 files changed, 28 insertions(+), 32 deletions(-) rename lib/src/main/java/me/onebone/toolbar/{SnapStrategy.kt => SnapConfig.kt} (93%) diff --git a/app/src/main/java/me/onebone/toolbar/ParallaxActivity.kt b/app/src/main/java/me/onebone/toolbar/ParallaxActivity.kt index b567a82..c7cf2ba 100644 --- a/app/src/main/java/me/onebone/toolbar/ParallaxActivity.kt +++ b/app/src/main/java/me/onebone/toolbar/ParallaxActivity.kt @@ -27,11 +27,7 @@ import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.MaterialTheme @@ -66,7 +62,7 @@ fun ParallaxEffect() { modifier = Modifier.fillMaxSize(), state = state, scrollStrategy = ScrollStrategy.EnterAlwaysCollapsed, - snapStrategy = SnapStrategy(), + snapConfig = SnapConfig(), toolbarModifier = Modifier.background(MaterialTheme.colors.primary), toolbar = { // Collapsing toolbar collapses its size as small as the that of diff --git a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt index 82f7846..51a00b8 100644 --- a/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt +++ b/lib/src/main/java/me/onebone/toolbar/CollapsingToolbarScaffold.kt @@ -96,7 +96,7 @@ fun CollapsingToolbarScaffold( modifier: Modifier, state: CollapsingToolbarScaffoldState, scrollStrategy: ScrollStrategy, - snapStrategy: SnapStrategy? = null, + snapConfig: SnapConfig? = null, toolbarModifier: Modifier = Modifier, toolbar: @Composable CollapsingToolbarScope.() -> Unit, body: @Composable () -> Unit @@ -104,7 +104,7 @@ fun CollapsingToolbarScaffold( val flingBehavior = ScrollableDefaults.flingBehavior() val nestedScrollConnection = remember(scrollStrategy, state) { - scrollStrategy.create(state, flingBehavior, snapStrategy) + scrollStrategy.create(state, flingBehavior, snapConfig) } val toolbarState = state.toolbarState diff --git a/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt b/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt index 10ac24b..9773541 100644 --- a/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt +++ b/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt @@ -35,31 +35,31 @@ enum class ScrollStrategy { override fun create( scaffoldState: CollapsingToolbarScaffoldState, flingBehavior: FlingBehavior, - snapStrategy: SnapStrategy?, + snapConfig: SnapConfig?, ): NestedScrollConnection = - EnterAlwaysNestedScrollConnection(scaffoldState, flingBehavior, snapStrategy) + EnterAlwaysNestedScrollConnection(scaffoldState, flingBehavior, snapConfig) }, EnterAlwaysCollapsed { override fun create( scaffoldState: CollapsingToolbarScaffoldState, flingBehavior: FlingBehavior, - snapStrategy: SnapStrategy?, + snapConfig: SnapConfig?, ): NestedScrollConnection = - EnterAlwaysCollapsedNestedScrollConnection(scaffoldState, flingBehavior, snapStrategy) + EnterAlwaysCollapsedNestedScrollConnection(scaffoldState, flingBehavior, snapConfig) }, ExitUntilCollapsed { override fun create( scaffoldState: CollapsingToolbarScaffoldState, flingBehavior: FlingBehavior, - snapStrategy: SnapStrategy?, + snapConfig: SnapConfig?, ): NestedScrollConnection = - ExitUntilCollapsedNestedScrollConnection(scaffoldState, flingBehavior, snapStrategy) + ExitUntilCollapsedNestedScrollConnection(scaffoldState, flingBehavior, snapConfig) }; internal abstract fun create( scaffoldState: CollapsingToolbarScaffoldState, flingBehavior: FlingBehavior, - snapStrategy: SnapStrategy?, + snapConfig: SnapConfig?, ): NestedScrollConnection } @@ -81,7 +81,7 @@ private class ScrollDelegate( internal class EnterAlwaysNestedScrollConnection( private val scaffoldState: CollapsingToolbarScaffoldState, private val flingBehavior: FlingBehavior, - private val snapStrategy: SnapStrategy? + private val snapConfig: SnapConfig? ): NestedScrollConnection { private val scrollDelegate = ScrollDelegate(scaffoldState.offsetYState) private val tracker = RelativeVelocityTracker(CurrentTimeProviderImpl()) @@ -131,7 +131,7 @@ internal class EnterAlwaysNestedScrollConnection( override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity { // TODO: Cancel expand/collapse animation inside onPreScroll - snapStrategy?.let { + snapConfig?.let { val isToolbarChangingOffset = scaffoldState.offsetY != 0 if (isToolbarChangingOffset) { // When the toolbar is hiding, it does it through changing the offset and does not @@ -150,7 +150,7 @@ internal class EnterAlwaysNestedScrollConnection( internal class EnterAlwaysCollapsedNestedScrollConnection( private val scaffoldState: CollapsingToolbarScaffoldState, private val flingBehavior: FlingBehavior, - private val snapStrategy: SnapStrategy?, + private val snapConfig: SnapConfig?, ): NestedScrollConnection { private val scrollDelegate = ScrollDelegate(scaffoldState.offsetYState) private val tracker = RelativeVelocityTracker(CurrentTimeProviderImpl()) @@ -208,7 +208,7 @@ internal class EnterAlwaysCollapsedNestedScrollConnection( } // TODO: Cancel expand/collapse animation inside onPreScroll - snapStrategy?.let { + snapConfig?.let { val isToolbarChangingOffset = scaffoldState.offsetY != 0 if (isToolbarChangingOffset) { // When the toolbar is hiding, it does it through changing the offset and does not @@ -227,7 +227,7 @@ internal class EnterAlwaysCollapsedNestedScrollConnection( internal class ExitUntilCollapsedNestedScrollConnection( private val scaffoldState: CollapsingToolbarScaffoldState, private val flingBehavior: FlingBehavior, - private val snapStrategy: SnapStrategy? + private val snapConfig: SnapConfig? ): NestedScrollConnection { private val tracker = RelativeVelocityTracker(CurrentTimeProviderImpl()) private val toolbarState = scaffoldState.toolbarState @@ -283,7 +283,7 @@ internal class ExitUntilCollapsedNestedScrollConnection( } // TODO: Cancel expand/collapse animation inside onPreScroll - snapStrategy?.let { scaffoldState.toolbarState.performSnap(it) } + snapConfig?.let { scaffoldState.toolbarState.performSnap(it) } return available.copy(y = available.y - left) } @@ -291,23 +291,23 @@ internal class ExitUntilCollapsedNestedScrollConnection( // TODO: Is there a better solution rather OptIn ExperimentalToolbarApi? @OptIn(ExperimentalToolbarApi::class) -private suspend fun CollapsingToolbarState.performSnap(strategy: SnapStrategy) { - if (progress > strategy.edge) { - expand(strategy.expandDuration) +private suspend fun CollapsingToolbarState.performSnap(snapConfig: SnapConfig) { + if (progress > snapConfig.edge) { + expand(snapConfig.expandDuration) } else { - collapse(strategy.collapseDuration) + collapse(snapConfig.collapseDuration) } } // TODO: Is there a better solution rather OptIn ExperimentalToolbarApi? @OptIn(ExperimentalToolbarApi::class) -private suspend fun CollapsingToolbarScaffoldState.performOffsetSnap(snapStrategy: SnapStrategy) { +private suspend fun CollapsingToolbarScaffoldState.performOffsetSnap(snapConfig: SnapConfig) { if (toolbarState.minHeight == 0) return val offsetProgress = 1f - (offsetY / toolbarState.minHeight).absoluteValue - if (offsetProgress > snapStrategy.edge) { - expandOffset(snapStrategy.expandDuration) + if (offsetProgress > snapConfig.edge) { + expandOffset(snapConfig.expandDuration) } else { - collapseOffset(snapStrategy.collapseDuration) + collapseOffset(snapConfig.collapseDuration) } } diff --git a/lib/src/main/java/me/onebone/toolbar/SnapStrategy.kt b/lib/src/main/java/me/onebone/toolbar/SnapConfig.kt similarity index 93% rename from lib/src/main/java/me/onebone/toolbar/SnapStrategy.kt rename to lib/src/main/java/me/onebone/toolbar/SnapConfig.kt index a2202d1..4c0b89b 100644 --- a/lib/src/main/java/me/onebone/toolbar/SnapStrategy.kt +++ b/lib/src/main/java/me/onebone/toolbar/SnapConfig.kt @@ -4,7 +4,7 @@ import androidx.annotation.FloatRange import androidx.compose.runtime.Immutable @Immutable -class SnapStrategy( +data class SnapConfig( @FloatRange(from = 0.0, to = 1.0) val edge: Float = CollapsingToolbarDefaults.Edge, val expandDuration: Int = CollapsingToolbarDefaults.ExpandDuration, val collapseDuration: Int = CollapsingToolbarDefaults.CollapseDuration diff --git a/lib/src/main/java/me/onebone/toolbar/ToolbarWithFabScaffold.kt b/lib/src/main/java/me/onebone/toolbar/ToolbarWithFabScaffold.kt index 426844c..c8633de 100644 --- a/lib/src/main/java/me/onebone/toolbar/ToolbarWithFabScaffold.kt +++ b/lib/src/main/java/me/onebone/toolbar/ToolbarWithFabScaffold.kt @@ -12,7 +12,7 @@ fun ToolbarWithFabScaffold( modifier: Modifier, state: CollapsingToolbarScaffoldState, scrollStrategy: ScrollStrategy, - snapStrategy: SnapStrategy? = null, + snapConfig: SnapConfig? = null, toolbarModifier: Modifier = Modifier, toolbar: @Composable CollapsingToolbarScope.() -> Unit, fab: @Composable () -> Unit, @@ -34,7 +34,7 @@ fun ToolbarWithFabScaffold( modifier = modifier, state = state, scrollStrategy = scrollStrategy, - snapStrategy = snapStrategy, + snapConfig = snapConfig, toolbarModifier = toolbarModifier, toolbar = toolbar, body = body From 3d27659029d7a0c178d7883263e93f09337fbd1e Mon Sep 17 00:00:00 2001 From: D067664 Date: Mon, 3 Jan 2022 10:11:42 +0100 Subject: [PATCH 11/11] Add check whether snap is needed - when toolbar is expanded or collapsed fully, do not perform snap (as it is not needed), this is the case, when progress == 0 or 1 - this improves performance and fixes a bug with horizontal scrolling in the CollapsingToolbarScaffold content --- lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt b/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt index 9773541..63c8dee 100644 --- a/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt +++ b/lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt @@ -292,9 +292,9 @@ internal class ExitUntilCollapsedNestedScrollConnection( // TODO: Is there a better solution rather OptIn ExperimentalToolbarApi? @OptIn(ExperimentalToolbarApi::class) private suspend fun CollapsingToolbarState.performSnap(snapConfig: SnapConfig) { - if (progress > snapConfig.edge) { + if (progress > snapConfig.edge && progress < 1f) { expand(snapConfig.expandDuration) - } else { + } else if (progress <= snapConfig.edge && progress > 0f){ collapse(snapConfig.collapseDuration) } }