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

2

5

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.

Diverticulum answered 13/7, 2022 at 23:20 Comment(0)
D
9

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())
                   )
               }
           }
        }
    }
}
Devilfish answered 14/7, 2022 at 5:43 Comment(2)
Thank you very much. I would like to know how to make Drawroungerect adjust to the entire size of the content. that is not having to pass calculated values. Do you know how to do that?Diverticulum
How can we make borders of a button or a card to have like these neon effects?Laux
W
0

To add glow like effect we can do a hack.

Step1: Make a duplication box/layout with stroke and make it blur.

Step2: Overlap original layout on top of it.

eg:

Box(contentAlignment = Alignment.Center){
    //Blur layout - will look like glow
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .height(64.dp)
            .blur(12.dp)
    ){
        Box(
            modifier = Modifier
                .fillMaxWidth()
                .height(64.dp)
                .padding(horizontal = 16.dp, vertical = 16.dp)
                .clip(RoundedCornerShape(20.dp))
                .border(width = 6.dp, 
                        color = Color.Red,
                        shape = RoundedCornerShape(20.dp))
        )
    }
    //Original layout
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .height(64.dp)
            .padding(horizontal = 16.dp, vertical = 16.dp)
            .clip(RoundedCornerShape(20.dp))
            .border(width = 2.dp, 
                    color = Color.White, 
                    shape = RoundedCornerShape(20.dp))
    )
}
Weihs answered 28/6 at 11:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.