https://kotlinlang.org logo
#compose
Title
# compose
c

Colton Idle

08/19/2021, 9:17 PM
I have a lazy column with a gradient background, and I want the gradient to be the entire height. BUT after I start scrolling I want to gradient to scroll up/off of the screen. Any Ideas on how to implement? I currently have a Box { GradientBackground() LazyColumn() } but the Gradient (of course) doesn't move up. Is there anything Col or LazyCol provide for this sort of thing? Kind of like a "first page background", and then a background for everything below the device height?
z

Zach Klippenstein (he/him) [MOD]

08/19/2021, 9:30 PM
Calculate an offset for the box background from the lazy list’s scroll state.
c

Colton Idle

08/19/2021, 9:48 PM
Box { GradientBackground() SolidBackground(offset = -screenHeight) LazyColumn() } and then LazyCol scroll state moves the SolidBackground offset towards a positive direction?
z

Zach Klippenstein (he/him) [MOD]

08/19/2021, 9:57 PM
i was thinking something like:
Copy code
Box(Modifier.background(Color.Magenta)) {
  GradientBackground(
    Modifier
      .fillMaxSize()
      .offset { IntOffset(0, -scrollState.value) }
  )
  LazyColumn(…)
}
c

Colton Idle

08/19/2021, 10:01 PM
Ah. That actually is nicer. So the box is actually the magenta color and the gradient just scrolls out of the way. I like it. Will give it a try right after I deal with some navigation issues. Thanks for the extra set of eyes!
👍🏻 1
Compose is like magic. I swear. It works great. Thanks for the tip @Zach Klippenstein (he/him) [MOD]
a

Ashu

08/20/2021, 5:11 AM
Just to make it a little more complex, how can we achieve the same gradient thing, but instead of the background, it applies to the content background. Like it happens in telegram where your chat message bubble have a gradient, top chat bubbles are let's say magenta in color and as you go down they become blue let's say. I am really fascinated by that. @Colton Idle @Zach Klippenstein (he/him) [MOD]
c

Colton Idle

08/20/2021, 5:51 AM
I think someone accomplished that in #compose channel. Try to search for it but I swear I saw it.
a

Ashu

08/20/2021, 3:53 PM
Cool thanks
c

Colton Idle

09/15/2021, 12:40 AM
@Zach Klippenstein (he/him) [MOD] so my requirements on this changed, and now after spending some time on this, I can't wrap my head around what the right solution to this is. Basically what I need to start with is a transparent box the size of the screen (not a gradient), and while I scroll up, then the solid magenta needs to come up from below. What I have "sorta" works, but the magenta doesn't come up soon enough, it comes up in the last portion of the scroll. This is what I have:
Copy code
val scrollState = rememberScrollState()
Box(modifier = Modifier.fillMaxSize()
) {
    Box(
        Modifier.matchParentSize().offset { IntOffset(0, scrollState.maxValue - scrollState.value) }.background(Color.Magenta)
    )
    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier =
        Modifier.fillMaxSize()
                .verticalScroll(scrollState)
Let me know if you have any other ideas for me as I feel like I'm missing something simple. Cheers
"Solved" it by using boxWithConstraints (I'm never really happy when I use boxWithConstraints because I know it shouldn't just be used everywhere) but I'm not sure if there's some other way
Copy code
val scrollState = rememberScrollState()
BoxWithConstraints(modifier = Modifier.fillMaxSize()) {
    val constraintBox = this@BoxWithConstraints
    Box(
        Modifier.matchParentSize()
            .offset {
                IntOffset(
                    0,
                    if (constraintBox.maxHeight.roundToPx() -
                        scrollState.value >= 0)
                        constraintBox.maxHeight.roundToPx() -
                            scrollState.value
                    else 0)
            }
Let me know if I'm overcomplicating things... but I will go with this for now. 😄
z

Zach Klippenstein (he/him) [MOD]

09/15/2021, 3:18 PM
You could do this with a custom layout as well, but this really isn’t that much code so if it works for you then great Since this is just a drawing effect, you could just draw the background yourself in a
drawBehind
modifier. That would eliminate the need for BwC and also only require a new draw pass on each scroll instead of a new composition + layout pass.
c

Colton Idle

09/15/2021, 3:26 PM
Haven't used drawBehind... Hm. Will give that a whirl. Just the kind of insight I was looking for. This screen is already doing a lot and showing a long lazy list and so I'm trying to optimize where possible. Thanks!
👋 hey zach, I went ahead and tried drawBehind, but not sure if I understand how I could do it without a BWC.
Copy code
Box(
    Modifier.matchParentSize()
        .drawBehind {
            drawRect(
                color = Color.Magenta,
                topLeft = Offset(size.width, -scrollState.value.toFloat()),
                size = Size(size.width, size.height))
        }
Maybe something is going over my head? or I've been staring at this for too long. lol
z

Zach Klippenstein (he/him) [MOD]

09/16/2021, 12:12 PM
Maybe the latter – if the left is at the
size.width
, the rectangle will always be off screen 😉 Also
size
has a default value that I think should work here. How about:
Copy code
.drawWithCache {
  // Don't trigger any more draw invalidations once scrolled past the first screen.
  val colorTop = derivedStateOf { (size.height - scrollState.value.toFloat()).coerceAtLeast(0f) }
  onDrawBehind {
    drawRect(
      color = Color.Magenta,
      topLeft = Offset(0f, colorTop)
    )
  }
}
c

Colton Idle

09/20/2021, 1:14 AM
Hey Zach! That worked! Need to study that api a bit more since it is totally going over my head... didn't even hear about the drawWithCachen until your comment.
68 Views