Search code examples
androidcanvasandroid-jetpack-composeandroid-canvasandroid-jetpack-compose-canvas

how to draw a square with stroke and neon glow with Jetpack Compose Canvas?


I need to draw a rounded square, something like drawRoundRect, but only the outline.

something like this.

enter image description here

this image is drawn by hand, as I said I need it to look like drawRoundRect but without outline (I don't want it to look hand drawn)

If you see it, the line has a gradient like this: red -> white -> red

I need that same gradient. If anyone has an idea or a solution I would greatly appreciate it.


Solution

  • You can draw it like this

    Column(modifier = Modifier
        .fillMaxSize()
        .background(Color.Black)) {
        val gradient = Brush.radialGradient(
            listOf(Color.Red.copy(.3f), Color.Red, Color.Red.copy(.3f)),
            center = Offset(300f,300f),
            radius = 500f
        )
    
        Canvas(modifier = Modifier.fillMaxSize()) {
            drawRoundRect(
                gradient,
                topLeft = Offset(100f, 100f),
                size = Size(400f, 400f),
                cornerRadius = CornerRadius(5.dp.toPx(), 5.dp.toPx()),
                style = Stroke(width = 6.dp.toPx())
            )
            drawRoundRect(
                Color.White,
                topLeft = Offset(100f, 100f),
                size = Size(400f, 400f),
                cornerRadius = CornerRadius(5.dp.toPx(), 5.dp.toPx()),
                style = Stroke(width = 2.dp.toPx())
            )
        }
    }
    

    This one will look better

    @Composable
    private fun NeonSample() {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .background(Color.Black)
        ) {
    
            val paint = remember {
                Paint().apply {
                    style = PaintingStyle.Stroke
                    strokeWidth = 30f
                }
            }
    
            val frameworkPaint = remember {
                paint.asFrameworkPaint()
            }
    
            val color = Color.Red
    
    
            Canvas(modifier = Modifier.fillMaxSize()) {
                this.drawIntoCanvas {
    
                    val transparent = color
                        .copy(alpha = 0f)
                        .toArgb()
    
                    frameworkPaint.color = transparent
    
                    frameworkPaint.setShadowLayer(
                        10f,
                        0f,
                        0f,
                        color
                            .copy(alpha = .5f)
                            .toArgb()
                    )
    
                    it.drawRoundRect(
                        left = 100f,
                        top = 100f,
                        right = 500f,
                        bottom = 500f,
                        radiusX = 5.dp.toPx(),
                        5.dp.toPx(),
                        paint = paint
                    )
    
                    drawRoundRect(
                        Color.White,
                        topLeft = Offset(100f, 100f),
                        size = Size(400f, 400f),
                        cornerRadius = CornerRadius(5.dp.toPx(), 5.dp.toPx()),
                        style = Stroke(width = 2.dp.toPx())
                    )
    
    
                    frameworkPaint.setShadowLayer(
                        30f,
                        0f,
                        0f,
                        color
                            .copy(alpha = .5f)
                            .toArgb()
                    )
    
    
                    it.drawRoundRect(
                        left = 600f,
                        top = 100f,
                        right = 1000f,
                        bottom = 500f,
                        radiusX = 5.dp.toPx(),
                        5.dp.toPx(),
                        paint = paint
                    )
    
                    drawRoundRect(
                        Color.White,
                        topLeft = Offset(600f, 100f),
                        size = Size(400f, 400f),
                        cornerRadius = CornerRadius(5.dp.toPx(), 5.dp.toPx()),
                        style = Stroke(width = 2.dp.toPx())
                    )
                }
            }
        }
    }
    

    enter image description here

    Edit

    Full size rounded rectangle. You can remove inset if you don't want to have padding for Canvas

    @Composable
    private fun NeonSample() {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .background(Color.Black)
        ) {
    
            val paint = remember {
                Paint().apply {
                    style = PaintingStyle.Stroke
                    strokeWidth = 30f
                }
            }
    
            val frameworkPaint = remember {
                paint.asFrameworkPaint()
            }
    
            val color = Color.Red
    
            val transparent = color
                .copy(alpha = 0f)
                .toArgb()
    
            frameworkPaint.color = transparent
    
            frameworkPaint.setShadowLayer(
                10f,
                0f,
                0f,
                color
                    .copy(alpha = .5f)
                    .toArgb()
            )
    
    
            Canvas(modifier = Modifier.fillMaxSize()) {
               inset(10.dp.toPx()){
                   this.drawIntoCanvas {
                       it.drawRoundRect(
                           left = 0f,
                           top = 0f,
                           right = size.width,
                           bottom = size.height,
                           radiusX = 5.dp.toPx(),
                           5.dp.toPx(),
                           paint = paint
                       )
    
                       drawRoundRect(
                           Color.White,
                           cornerRadius = CornerRadius(5.dp.toPx(), 5.dp.toPx()),
                           style = Stroke(width = 2.dp.toPx())
                       )
                   }
               }
            }
        }
    }