Skip to content

Commit ca373fe

Browse files
committed
offset collapsing animation implementation
1 parent ab42e1b commit ca373fe

File tree

3 files changed

+57
-11
lines changed

3 files changed

+57
-11
lines changed

lib/src/main/java/me/onebone/toolbar/CollapsingToolbar.kt

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import androidx.compose.foundation.gestures.FlingBehavior
3131
import androidx.compose.foundation.gestures.ScrollScope
3232
import androidx.compose.foundation.gestures.ScrollableState
3333
import androidx.compose.runtime.Composable
34+
import androidx.compose.runtime.MutableState
3435
import androidx.compose.runtime.Stable
3536
import androidx.compose.runtime.getValue
3637
import androidx.compose.runtime.mutableStateOf
@@ -136,6 +137,7 @@ class CollapsingToolbarState(
136137
)
137138
fun feedScroll(value: Float): Float = dispatchRawDelta(value)
138139

140+
// TODO: A strange jump in snap speed is often observed
139141
@ExperimentalToolbarApi
140142
suspend fun expand(duration: Int = CollapsingToolbarDefaults.EXPAND_DURATION) {
141143
val anim = AnimationState(height.toFloat())
@@ -149,6 +151,7 @@ class CollapsingToolbarState(
149151
}
150152
}
151153

154+
// TODO: A strange jump in snap speed is often observed
152155
@ExperimentalToolbarApi
153156
suspend fun collapse(duration: Int = CollapsingToolbarDefaults.COLLAPSE_DURATION) {
154157
val anim = AnimationState(height.toFloat())
@@ -162,6 +165,46 @@ class CollapsingToolbarState(
162165
}
163166
}
164167

168+
@ExperimentalToolbarApi
169+
suspend fun expandOffset(snapStrategy: SnapStrategy, offsetY: MutableState<Int>) {
170+
val anim = AnimationState(offsetY.value.toFloat())
171+
172+
anim.animateTo(0f, tween(snapStrategy.expandDuration)) {
173+
offsetY.value = value.toInt()
174+
}
175+
}
176+
177+
@ExperimentalToolbarApi
178+
suspend fun collapseOffset(snapStrategy: SnapStrategy, offsetY: MutableState<Int>) {
179+
val anim = AnimationState(offsetY.value.toFloat())
180+
181+
anim.animateTo(-minHeight.toFloat(), tween(snapStrategy.collapseDuration)) {
182+
offsetY.value = value.toInt()
183+
}
184+
}
185+
186+
// TODO: Is there a better solution rather OptIn ExperimentalToolbarApi?
187+
@OptIn(ExperimentalToolbarApi::class)
188+
internal suspend fun processSnap(strategy: SnapStrategy) {
189+
if (progress > strategy.edge) {
190+
expand(strategy.expandDuration)
191+
} else {
192+
collapse(strategy.collapseDuration)
193+
}
194+
}
195+
196+
// TODO: Is there a better solution rather OptIn ExperimentalToolbarApi?
197+
@OptIn(ExperimentalToolbarApi::class)
198+
internal suspend fun processOffsetSnap(snapStrategy: SnapStrategy, offsetY: MutableState<Int>) {
199+
val offsetProgress =
200+
1f - ((offsetY.value / (minHeight / 100f)) / 100f).absoluteValue
201+
if (offsetProgress > snapStrategy.edge) {
202+
expandOffset(snapStrategy, offsetY)
203+
} else {
204+
collapseOffset(snapStrategy, offsetY)
205+
}
206+
}
207+
165208
/**
166209
* @return Remaining velocity after fling
167210
*/

lib/src/main/java/me/onebone/toolbar/ScrollStrategy.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,19 @@ internal class EnterAlwaysCollapsedNestedScrollConnection(
192192
dy
193193
}
194194

195+
// TODO: Cancel expand/collapse animation inside onPreScroll
196+
snapStrategy?.let {
197+
val isToolbarChangingOffset = offsetY.value != 0//toolbarState.progress == 0f
198+
if (isToolbarChangingOffset) {
199+
// When the toolbar is hiding, it does it through changing the offset and does not
200+
// change its height, so we must process not the snap of the toolbar, but the
201+
// snap of its offset.
202+
toolbarState.processOffsetSnap(it, offsetY)
203+
} else {
204+
toolbarState.processSnap(it)
205+
}
206+
}
207+
195208
return available.copy(y = available.y - left)
196209
}
197210
}

lib/src/main/java/me/onebone/toolbar/SnapStrategy.kt

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,4 @@ class SnapStrategy(
88
@FloatRange(from = 0.0, to = 1.0) val edge: Float = CollapsingToolbarDefaults.EDGE,
99
val expandDuration: Int = CollapsingToolbarDefaults.EXPAND_DURATION,
1010
val collapseDuration: Int = CollapsingToolbarDefaults.COLLAPSE_DURATION
11-
)
12-
13-
// TODO: Is there a better solution rather OptIn ExperimentalToolbarApi?
14-
@OptIn(ExperimentalToolbarApi::class)
15-
internal suspend fun CollapsingToolbarState.processSnap(strategy: SnapStrategy) {
16-
if (progress > strategy.edge) {
17-
expand(strategy.expandDuration)
18-
} else {
19-
collapse(strategy.collapseDuration)
20-
}
21-
}
11+
)

0 commit comments

Comments
 (0)