`Modifier.scrollable` and `Modifier.horizontalScro...
# compose
a
Modifier.scrollable
and
Modifier.horizontalScroll
clip their children differently. Is this a bug? Code in 🧵.
This is the code that crops the box. This is the first image.
Copy code
Box(
  Modifier
    .size(70.dp)
    .scrollable(
      orientation = Orientation.Horizontal,
      state = rememberScrollableState { it }
    )
) {
  Box(
    Modifier
      .size(200.dp)
      .border(10.dp, Color.Green)
      .background(Color.Red)
  )
}
And this is the
horizontalScroll
version. This is the second image.
Copy code
Box(
  Modifier
    .size(70.dp)
    .horizontalScroll(rememberScrollState())
) {
  Box(
    Modifier
      .size(200.dp)
      .border(10.dp, Color.Green)
      .background(Color.Red)
  )
}
When I do use
Modifier.scrollable
to move the offset of the child, the full
200.dp
isn't there. It's been cut.
i
Is it just a copy/paste error that you're using
orientation = Orientation.Vertical,
in your
scrollable
code? That would be vertically scrolling, not horizontal scrolling
a
Oh I've just seen the code that does the clipping in
horizontalScroll
. See below. Shouldn't
Modifier.scrollable
do something similar? I can't do it from my own code, easily, since
clipScrollableContainer
is private in the compose libs.
Copy code
val layout = ScrollingLayoutModifier(state, reverseScrolling, isVertical)
        semantics.then(scrolling).clipScrollableContainer(isVertical).then(layout)
Yes, Ian. Copy and paste error. Thanks for pointing it out
It might be worth mentioning the sample code doesn't actually scroll anything, just outputs a number, so there's no good example of using
Modifier.scrollable
to scroll a child that's bigger than its parent. https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/[…]eSamples.kt;l=57;drc=5f80de6c0af73c334fbd8702e5e5745844fb42b0 Surely this a bug?
a
This is the intended behavior.
Modifier.scrollable()
is a relatively low-level API that you can use to create your own scrollable component. The difference is not caused by how they clip their children. It's because
Modifier.scrollable()
doesn't automatically measure its children with infinite max width, which
Modifier.horizontalScroll()
does.
a
I'm wondering how I can force
scrollable
to mesaure its children as so. Currently this mean
scrollable
without extra code doesn't scroll the child. And that seems rather un-intuitive. It, at least, should be explained and documented.
a
If you just want the normal scrolling behavior, why not use
Modifier.horizontalScroll()
?
Modifier.scrollable()
is always used with custom layout since you need to specify the scrolling logic yourself. Something like:
Copy code
Layout(
    content = { /*TODO*/ },
    modifier = Modifier.scrollable(...)
) { measurables, constraints ->
    val childrenConstraints = constraints.copy(maxWidth = Constraints.Infinity)
    val placeables = measurables.fastMap { it.measure(childrenConstraints) }
    layout(constraints.maxWidth, constraints.maxHeight) {
        placeables.fastForEach { it.place(0, 0) }
    }
}
👍 1
a
I'm exploring the APIs currently. And it's unfortunately neither the documentation and or API call itself for
scrollable
scrolls anything or at least tells you that you need to do more to scroll than just use the modifier.
a
The doc mentions it:
Users should update their state themselves using default [ScrollableState] and its
consumeScrollDelta
callback or by implementing [ScrollableState] interface manually and reflect their own state in UI when using this component.
And "reflect their own state in UI" includes using the scroll offset to show different parts of the content. Basically if you just want to make a component scrollable, there's literally no reason to use this modifier. This modifier is for cases that the high-level APIs don't fit, where you usually have some custom layout logic anyway. For example, the Pager in accompanist used to use this modifier.
a
If there's no reason to use the modifier then it should be advertised as such. The docs mentions changing the offset. But they don't mention laying out the child.