8

I would like to implement a bounce "iOS-like" effect on a LazyColumn but have no clue on how to implement it.

Expected result is : iOS like over scroll effect on Android (using RecyclerView) with bounce on top and bottom of the list.

I went through snapper by Chris Bane : https://github.com/chrisbanes/snapper but it doesn't seem to support it.

My guess is that I would need to create some LazyListScope extension but it's hard to figure out.

Thank you in advance!

Yogi Bear
  • 603
  • 8
  • 22

1 Answers1

3

That is not possible at the moment 03.14.2022

If you see the source code at Scrollable.kt class inside the androidx.compose.foundation.gestures package there is a extension function Modifier.scrollable

internal fun Modifier.scrollable(
    state: ScrollableState,
    orientation: Orientation,
    overScrollController: OverScrollController?,
    enabled: Boolean = true,
    reverseDirection: Boolean = false,
    flingBehavior: FlingBehavior? = null,
    interactionSource: MutableInteractionSource? = null
): Modifier

This method contains OverScrollController that handles the over-scroll functionally, unfortunately this method is internal so we cannot use it outside of its package.

If we see the Scroll.kt class inside the androidx.compose.foundation package we can see the extension method scroll() that is also private and is used by Modifier.verticalScroll and Modifier.horizontalScroll , is using the default over-scroll controller

private fun Modifier.scroll(
    state: ScrollState,
    reverseScrolling: Boolean,
    flingBehavior: FlingBehavior?,
    isScrollable: Boolean,
    isVertical: Boolean
) = composed(
    factory = {
        val overScrollController = rememberOverScrollController()
  ...
@Composable
@OptIn(ExperimentalFoundationApi::class)
internal actual fun rememberOverScrollController(): OverScrollController {
    val context = LocalContext.current
    val config = LocalOverScrollConfiguration.current
    return remember(context, config) {
        if (config != null) {
            AndroidEdgeEffectOverScrollController(context, config)
        } else {
            NoOpOverscrollController
        }
    }
}

At this moment we can only disable the default over-scroll configurations as seen in this answer. Or set out custom configurations, that can only set color and offset and is only available for API < 31

 CompositionLocalProvider(
     LocalOverScrollConfiguration provides OverScrollConfiguration(
         glowColor = Color.Red, forceShowAlways = true, PaddingValues(10.dp)
     )
 ) {
     // your row, colum
}

enter image description here

I have tried implementing my own logic using pointerInteropFilter to detect the offset and verticalScroll for the scrolling capabilities. But when I include pointerInteropFilter it interacted with the verticalScroll and the Column becomes laggy and does not detect the proper events!

Column(
    verticalArrangement = Arrangement.SpaceEvenly,
    horizontalAlignment = Alignment.CenterHorizontally,
    modifier = Modifier
        .fillMaxSize()
        .offset {
            IntOffset(0, offset.roundToInt())
        } 
        .pointerInteropFilter { motionEvent ->    
            
            when (motionEvent.action) {
                MotionEvent.ACTION_DOWN -> {
                    startFingerPositionY = motionEvent.rawY
                }
                MotionEvent.ACTION_MOVE, MotionEvent.ACTION_UP -> {
                    offsetY = startFingerPositionY - motionEvent.rawY
                    startFingerPositionY = motionEvent.rawY    
           
                }
            }    
            true 
        }
        .verticalScroll(state = state)
){
    
} 

So it is up to Google to allow custom over-scroll effects, and lets hope in the future, they will do something about it!

slaviboy
  • 1,407
  • 17
  • 27