11package top.yukonga.miuix.kmp.utils
22
33import androidx.compose.animation.core.Animatable
4- import androidx.compose.animation.core.AnimationState
54import androidx.compose.animation.core.AnimationVector1D
6- import androidx.compose.animation.core.DecayAnimationSpec
75import androidx.compose.animation.core.Spring.StiffnessMediumLow
8- import androidx.compose.animation.core.animateDecay
9- import androidx.compose.animation.core.exponentialDecay
106import androidx.compose.animation.core.spring
11- import androidx.compose.animation.rememberSplineBasedDecay
12- import androidx.compose.foundation.gestures.FlingBehavior
13- import androidx.compose.foundation.gestures.ScrollScope
14- import androidx.compose.foundation.gestures.ScrollableState
15- import androidx.compose.foundation.lazy.LazyListState
16- import androidx.compose.foundation.lazy.LazyRow
177import androidx.compose.runtime.Composable
188import androidx.compose.runtime.Stable
199import androidx.compose.runtime.getValue
@@ -33,7 +23,6 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll
3323import androidx.compose.ui.platform.LocalDensity
3424import androidx.compose.ui.unit.Velocity
3525import kotlinx.coroutines.launch
36- import top.yukonga.miuix.kmp.basic.LazyColumn
3726import kotlin.math.abs
3827import kotlin.math.exp
3928import kotlin.math.sign
@@ -87,9 +76,8 @@ fun Modifier.overScrollVertical(
8776 scrollEasing : ((currentOffset: Float , newOffset: Float ) -> Float )? = null,
8877 springStiff : Float = OutBoundSpringStiff ,
8978 springDamp : Float = OutBoundSpringDamp ,
90- onOverscroll : ((Boolean ) -> Unit )? = null,
9179 isEnabled : () -> Boolean = { platform() == Platform .Android }
92- ): Modifier = overScrollOutOfBound(isVertical = true , nestedScrollToParent, scrollEasing, springStiff, springDamp, onOverscroll, isEnabled)
80+ ): Modifier = overScrollOutOfBound(isVertical = true , nestedScrollToParent, scrollEasing, springStiff, springDamp, isEnabled)
9381
9482/* *
9583 * @see overScrollOutOfBound
@@ -100,9 +88,8 @@ fun Modifier.overScrollHorizontal(
10088 scrollEasing : ((currentOffset: Float , newOffset: Float ) -> Float )? = null,
10189 springStiff : Float = OutBoundSpringStiff ,
10290 springDamp : Float = OutBoundSpringDamp ,
103- onOverscroll : ((Boolean ) -> Unit )? = null,
10491 isEnabled : () -> Boolean = { platform() == Platform .Android }
105- ): Modifier = overScrollOutOfBound(isVertical = false , nestedScrollToParent, scrollEasing, springStiff, springDamp, onOverscroll, isEnabled)
92+ ): Modifier = overScrollOutOfBound(isVertical = false , nestedScrollToParent, scrollEasing, springStiff, springDamp, isEnabled)
10693
10794/* *
10895 * OverScroll effect for scrollable Composable.
@@ -118,7 +105,6 @@ fun Modifier.overScrollHorizontal(
118105 * The current default easing comes from iOS, you don't need to modify it!
119106 * @param springStiff springStiff for overscroll effect,For better user experience, the new value is not recommended to be higher than[StiffnessMediumLow]
120107 * @param springDamp springDamp for overscroll effect,generally do not need to set。
121- * @param onOverscroll Callback when the overscroll state changes, the parameter is whether the current state is Overscrolling.
122108 * @param isEnabled Whether to enable Overscroll effect, default is true.
123109 */
124110@Stable
@@ -129,11 +115,9 @@ fun Modifier.overScrollOutOfBound(
129115 scrollEasing : ((currentOffset: Float , newOffset: Float ) -> Float )? ,
130116 springStiff : Float = OutBoundSpringStiff ,
131117 springDamp : Float = OutBoundSpringDamp ,
132- onOverscroll : ((Boolean ) -> Unit )? = null,
133118 isEnabled : () -> Boolean = { platform() == Platform .Android }
134119): Modifier = composed {
135120 if (! isEnabled()) return @composed this
136- val onOverscroll by rememberUpdatedState(onOverscroll)
137121 val nestedScrollToParent by rememberUpdatedState(nestedScrollToParent)
138122 val scrollEasing by rememberUpdatedState(scrollEasing ? : DefaultParabolaScrollEasing )
139123 val springStiff by rememberUpdatedState(springStiff)
@@ -174,15 +158,13 @@ fun Modifier.overScrollOutOfBound(
174158 // sign changed, coerce to start scrolling and exit
175159 return if (sign(offset) != sign(offsetAtLast)) {
176160 offset = 0f
177- onOverscroll?.invoke(false )
178161 if (isVertical) {
179162 Offset (x = available.x - realAvailable.x, y = available.y - realAvailable.y + realOffset)
180163 } else {
181164 Offset (x = available.x - realAvailable.x + realOffset, y = available.y - realAvailable.y)
182165 }
183166 } else {
184167 offset = offsetAtLast
185- onOverscroll?.invoke(true )
186168 if (isVertical) {
187169 Offset (x = available.x - realAvailable.x, y = available.y)
188170 } else {
@@ -194,14 +176,13 @@ fun Modifier.overScrollOutOfBound(
194176 override fun onPostScroll (consumed : Offset , available : Offset , source : NestedScrollSource ): Offset {
195177 // Found fling behavior in the wrong direction.
196178 if (source != NestedScrollSource .UserInput ) {
197- return dispatcher.dispatchPreScroll( available, source)
179+ return dispatcher.dispatchPostScroll(consumed, available, source)
198180 }
199181 val realAvailable = when {
200182 nestedScrollToParent -> available - dispatcher.dispatchPostScroll(consumed, available, source)
201183 else -> available
202184 }
203185 offset = scrollEasing(offset, if (isVertical) realAvailable.y else realAvailable.x)
204- onOverscroll?.invoke(abs(offset) > visibilityThreshold)
205186 return if (isVertical) {
206187 Offset (x = available.x - realAvailable.x, y = available.y)
207188 } else {
@@ -210,7 +191,6 @@ fun Modifier.overScrollOutOfBound(
210191 }
211192
212193 override suspend fun onPreFling (available : Velocity ): Velocity {
213- onOverscroll?.invoke(false )
214194 if (::lastFlingAnimator.isInitialized && lastFlingAnimator.isRunning) {
215195 lastFlingAnimator.stop()
216196 }
@@ -240,7 +220,6 @@ fun Modifier.overScrollOutOfBound(
240220 }
241221
242222 override suspend fun onPostFling (consumed : Velocity , available : Velocity ): Velocity {
243- onOverscroll?.invoke(false )
244223 val realAvailable = when {
245224 nestedScrollToParent -> available - dispatcher.dispatchPostFling(consumed, available)
246225 else -> available
@@ -265,55 +244,3 @@ fun Modifier.overScrollOutOfBound(
265244 if (isVertical) translationY = offset else translationX = offset
266245 }
267246}
268-
269-
270- /* *
271- * You should use it with [overScrollVertical]
272- * @param decaySpec You can use instead [rememberSplineBasedDecay]
273- * @param getScrollState Pass in your [ScrollableState], for [LazyColumn]/[LazyRow] , it's [LazyListState]
274- */
275- @Composable
276- fun rememberOverscrollFlingBehavior (
277- decaySpec : DecayAnimationSpec <Float > = exponentialDecay(),
278- getScrollState : () -> ScrollableState ,
279- ): FlingBehavior = remember(decaySpec, getScrollState) {
280- object : FlingBehavior {
281- /* *
282- * - We should check it every frame of fling
283- * - Should stop fling when returning true and return the remaining speed immediately.
284- * - Without this detection, scrollBy() will continue to consume velocity,
285- * which will cause a velocity error in nestedScroll.
286- */
287- private val Float .canNotBeConsumed: Boolean // this is Velocity
288- get() {
289- val state = getScrollState()
290- return ! (this < 0 && state.canScrollBackward || this > 0 && state.canScrollForward)
291- }
292-
293- override suspend fun ScrollScope.performFling (initialVelocity : Float ): Float {
294- if (initialVelocity.canNotBeConsumed) {
295- return initialVelocity
296- }
297- return if (abs(initialVelocity) > 1f ) {
298- var velocityLeft = initialVelocity
299- var lastValue = 0f
300- AnimationState (
301- initialValue = 0f ,
302- initialVelocity = initialVelocity,
303- ).animateDecay(decaySpec) {
304- val delta = value - lastValue
305- val consumed = scrollBy(delta)
306- lastValue = value
307- velocityLeft = this .velocity
308- // avoid rounding errors and stop if anything is unconsumed
309- if (abs(delta - consumed) > 0.5f || velocityLeft.canNotBeConsumed) {
310- cancelAnimation()
311- }
312- }
313- velocityLeft
314- } else {
315- initialVelocity
316- }
317- }
318- }
319- }
0 commit comments