Compose drawWithContent modifier and MotionLayout bizarre bug

85 Views Asked by At

I built a screen with Compose MotionLayout.

My dependencies are:

  • androidx.constraintlayout:constraintlayout-compose:1.0.1
  • Platform dev.chrisbanes.compose:compose-bom:2023.02.00-beta03
  • androidx.compose.material3:material3:1.2.0-alpha06
  • Compose 1.5.0

I have an Image defined as:

MotionLayout(
    /* ... */
    motionScene = MotionScene(motionScene),
    progress = progress
) {
    Image(
        modifier = Modifier
            .clip(avatarShape)
            .layoutId("avatar"),
        painter = painterResource(id = R.drawable.chat_pattern_png),
        contentDescription = null,
        contentScale = ContentScale.Crop
    )
/* ... */
}

Which is constrained like this:

{
  ConstraintSets: {
    start: {
      avatar: {
        width: 45,
        height: 45,
        start: ['parent', 'start', 16],
        top: ['parent', 'top', 16]
      },
      // ...
    },
    end: {
      avatar: {
        width: 'parent',
        height: '1:1',
        start: ['parent', 'start'],
        top: ['parent', 'top'],
      },
      // ...
    }
  }
}

This results in almost what I want:

Image with no gradients

But I needed to add some gradients to make content that ends up above the image readable. I didn't want to add Boxes to my layout so I drew above the image with a drawWithContent modifier:

val breakpointTransitionProgress by animateFloatAsState(
    targetValue = if (progress <= .7f) 0f else 1f
)
//...
Image(
    modifier = Modifier
        .clip(avatarShape)
        .drawWithContent {
            drawContent()
            drawRect(
                brush = Brush.verticalGradient(
                    0f to Color.Black.copy(.4f),
                    1f to Color.Transparent,
                    endY = size.height * .3f * breakpointTransitionProgress
                ),
                size = size.copy(height = size.height * .3f * breakpointTransitionProgress)
            )
            drawRect(
                brush = Brush.verticalGradient(
                    0f to Color.Transparent,
                    1f to Color.Black.copy(.4f),
                    startY = size.height * lerp(1f, .7f, breakpointTransitionProgress),
                ),
                size = size.copy(height = size.height * .3f),
                topLeft = Offset(
                    x = 0f,
                    y = size.height * lerp(1f, .7f, breakpointTransitionProgress)
                )
            )
        }
        .layoutId("avatar"),
    painter = painterResource(id = R.drawable.chat_pattern_png),
    contentDescription = null,
    contentScale = ContentScale.Crop
)

Which is where I encountered the most bizarre bug I've ever seen. Look at the icons in Bottom Navigation - they flicker, as if those gradients are applied to them too.

Image with gradients

I can't even begin to guess WTF is happening here since this MotionLayout is a destination inside a NavHost inside the content slot of the topmost Scaffold, while BottomNavigationItems are inside the bottomBar slot of the same Scaffold. I just can't see how drawing above the image can influence them.

What could I have done wrong? Is this a dependency bug? Should I report it?

0

There are 0 best solutions below