Does anyone know how to properly implement the `on...
# compose
n
Does anyone know how to properly implement the
onPreFling
method in
NestedScrollConnection
? I'm trying to create a nested layout, but I'm encountering some strange issues. 🙏 During the
onPreScroll
or
onPostScroll
process, if it's not a fast fling or if I try to scroll by dragging, the nested layout doesn't scroll properly. 🤔
Here is Code:
Copy code
@Composable
internal fun CollapsingLayout(
  collapsingTop: @Composable BoxScope.() -> Unit,
  bodyContent: @Composable BoxScope.() -> Unit,
  topBar: @Composable (Float) -> Unit,
  modifier: Modifier = Modifier,
) {
  var collapsingTopHeight by remember { mutableFloatStateOf(0f) }
  var topBarHeight by remember { mutableFloatStateOf(0f) }
  var topBarAlpha by remember { mutableFloatStateOf(0f) }

  var offset by remember { mutableFloatStateOf(0f) }

  fun calculateOffset(delta: Float): Offset {
    val oldOffset = offset
    val newOffset = (oldOffset + delta).coerceIn(-(collapsingTopHeight-topBarHeight), 0f)
    offset = newOffset
    topBarAlpha = abs(offset / (collapsingTopHeight - topBarHeight))
    return Offset(0f, newOffset - oldOffset)
  }

  val nestedScrollConnection = remember {
    object : NestedScrollConnection {
      override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
        return when {
          available.y >= 0 -> Offset.Zero
          else -> calculateOffset(available.y)
        }
      }

      override fun onPostScroll(
        consumed: Offset,
        available: Offset,
        source: NestedScrollSource,
      ): Offset {
        return when {
          available.y <= 0 -> Offset.Zero
          else -> calculateOffset(available.y)
        }
      }
    }
  }

  Box(
    modifier = modifier
      .fillMaxSize()
      .nestedScroll(nestedScrollConnection),
  ) {
    Box(
      modifier = Modifier
        .onSizeChanged { size ->
          collapsingTopHeight = size.height.toFloat()
        }
        .offset { IntOffset(x = 0, y = offset.roundToInt()) },
      content = collapsingTop,
    )
    Box(
      modifier = Modifier.offset {
        IntOffset(
          x = 0,
          y = (collapsingTopHeight + offset).roundToInt()
        )
      },
      content = bodyContent,
    )
    Box(
      modifier = Modifier
        .onSizeChanged {
          topBarHeight = it.height.toFloat()
        },
    ) {
      topBar(topBarAlpha)
    }
  }
}
n
I had similar scrolling issue while creating custom collapsing toolbar as well. Disabling overscroll effect for the screen fixed it for me
Copy code
CompositionLocalProvider(
                LocalOverscrollConfiguration provides null,
                content = {
   // Screen content
}
)
n
@Nazar Rusnak thank you ! but it doesn't work for me 😞, I don't think this is an overscrolling issue, but rather an issue with the
onPreFling
method inside the
NestedScollConnection
n
wait, I am also writing a client for mastodon, lol
it looks like pretty cool !! let me check
m
I tried multiple solutions that used NestedScrollConnection, though I couldn’t make them work properly, so I ended up with the following solution https://gist.github.com/Xlopec/573ec12978617e00434fd89dc502e932
j
cc @levima
a
I can't reproduce the issue without further code, but when I encountered this issue before in my project, it turned out to be caused by rounding error when calculating the delta to consume. What I did to fix the issue was something like this:
Copy code
fun calculateOffset(delta: Float): Offset {
    ...
    val consumed = newOffset - oldOffset
    return Offset(0f, if (abs(consumed - available) < Epsilon) available else consumed)
}

// Elsewhere in the file
private const val Epsilon = 1e-4f
n
@Albert Chang it works ! If I change from consumed(newOffset - oldOffset) to delta (available. y), it really solves the problem of scroll up and getting stuck somewhere! But there is still a problem with my
onPostScroll
. It cannot directly slide me from LazyColumn to the top, and I must wait for the LazyColumn to slide to the end before dragging again to reach the top. Do you know what caused this?
demo.mp4
a
Not sure if it's related but always consuming all the delta is wrong. Please try what I suggested first.