kotlinandroid-jetpack-compose

create transparent box with colored rounded corners in jetpack compose


I want to create a Box with Transparent background with rounded corners that is for example Red (In jetpack compose android kotlin). I can put two Box on each other that below one is Green and top one in Red with rounded corners, but the issue is that if i want to Transparent the top one, we will see green, but i don't want to green be shown, i want transparent

I want exactly something like this :

enter image description here


Solution

  • You can achieve this using BlendModes.

    First, set compositionStrategy to CompositingStrategy.Offscreen in graphicsLayer.

    Then apply BlendMode to Rectangle while drawing rounded rectangle to get their intersection and remove content of Composable from it.

    Result

    enter image description here

    Implementation

    @Preview
    @Composable
    fun TransparentBoxTest() {
    
        Column(
            modifier = Modifier
                .padding(16.dp)
                .drawChecker()
        ) {
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .aspectRatio(1f)
                    .graphicsLayer {
                        compositingStrategy = CompositingStrategy.Offscreen
                    }
                    .drawWithContent {
    
                        //Destination
                        drawContent()
    
                        // Source
                        drawRoundRect(
                            color = Color.Blue,
                            cornerRadius = CornerRadius(64.dp.toPx()),
                        )
    
                        drawRect(
                            color = Color.Red,
                            blendMode = BlendMode.SrcOut
                        )
    
                    }
            ) {
            }
        }
    }
    

    Modifier to draw checker pattern on parent Column

    fun Modifier.drawChecker() = this.then(
        drawBehind {
            val width = this.size.width
            val height = this.size.height
    
            val checkerWidth = 10.dp.toPx()
            val checkerHeight = 10.dp.toPx()
    
            val horizontalSteps = (width / checkerWidth).toInt()
            val verticalSteps = (height / checkerHeight).toInt()
    
            for (y in 0..verticalSteps) {
                for (x in 0..horizontalSteps) {
                    val isGrayTile = ((x + y) % 2 == 1)
                    drawRect(
                        color = if (isGrayTile) Color.LightGray else Color.White,
                        topLeft = Offset(x * checkerWidth, y * checkerHeight),
                        size = Size(checkerWidth, checkerHeight)
                    )
                }
            }
        }
    )