最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Neon Line using drawLine method in Canvas Android Jetpack Compose - Stack Overflow

programmeradmin4浏览0评论

I am new to android development and have made a canvas of my own, I am using drawLine for writing on the canvas, but i want to have neon color in it and should have smooth drawing also.

androidxpose.foundation.Canvas(
            modifier = Modifier
                .fillMaxSize()
                .pointerInput(true) {
                    detectDragGestures { change, dragAmount ->
                        change.consume()

                        val line = Line(
                            start = change.position - dragAmount,
                            end = change.position,
                            color = currentColor
                        )
                        lines.add(line)
                    }
                }

        ) {
            val neonGradient = Brush.linearGradient(
                colors = listOf(
                    Color.Red.copy(alpha = 0.7f),
                    Color.White,
                    Color.Red.copy(alpha = 0.7f)
                )
            )

            lines.forEach { line->
                drawLine(
                    brush = neonGradient,
                    start = line.start,
                    end = line.end,
                    strokeWidth = line.strokeWidth,
                    cap = StrokeCap.Round
                )
            }
        }

I wrote the above for this, but not getting the neon color as expected can anyone help with this.

I am new to android development and have made a canvas of my own, I am using drawLine for writing on the canvas, but i want to have neon color in it and should have smooth drawing also.

androidx.compose.foundation.Canvas(
            modifier = Modifier
                .fillMaxSize()
                .pointerInput(true) {
                    detectDragGestures { change, dragAmount ->
                        change.consume()

                        val line = Line(
                            start = change.position - dragAmount,
                            end = change.position,
                            color = currentColor
                        )
                        lines.add(line)
                    }
                }

        ) {
            val neonGradient = Brush.linearGradient(
                colors = listOf(
                    Color.Red.copy(alpha = 0.7f),
                    Color.White,
                    Color.Red.copy(alpha = 0.7f)
                )
            )

            lines.forEach { line->
                drawLine(
                    brush = neonGradient,
                    start = line.start,
                    end = line.end,
                    strokeWidth = line.strokeWidth,
                    cap = StrokeCap.Round
                )
            }
        }

I wrote the above for this, but not getting the neon color as expected can anyone help with this.

Share Improve this question asked Feb 7 at 4:18 codeKarcodeKar 212 silver badges4 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

One of the ways of achieving this in Compose is using a Paint with shadowLayer.

val paint = remember {
    Paint().apply {
        style = PaintingStyle.Stroke
        strokeWidth = 20f
        strokeCap = StrokeCap.Round

        this.asFrameworkPaint().apply {
            val transparent = color
                .copy(alpha = 0f)
                .toArgb()

            this.color = transparent
        }

        asFrameworkPaint().setShadowLayer(
            35f * phase,
            0f,
            0f,
            color
                .copy(alpha = phase)
                .toArgb()
        )
    }
}

and draw path with

this.drawIntoCanvas {

    it.drawPath(path, paint)

    drawPath(
        color = Color.White.copy((0.7f + phase).coerceAtMost(1f)),
        path = path,
        style = Stroke(width = 4.dp.toPx(), cap = StrokeCap.Round, join = StrokeJoin.Round)
    )
}

Full code

Gesture in sample below is a custom gesture i wrote to draw on Canvas as counterPart of touch events for view which does not have slope pass threshold like drag.

@Composable
private fun NeonDrawingSample() {

    var motionEvent by remember { mutableStateOf(MotionEvent.Idle) }
    // This is our motion event we get from touch motion
    var currentPosition by remember { mutableStateOf(Offset.Unspecified) }
    // This is previous motion event before next touch is saved into this current position
    var previousPosition by remember { mutableStateOf(Offset.Unspecified) }


    val transition: InfiniteTransition = rememberInfiniteTransition()

    // Infinite phase animation for PathEffect
    val phase by transition.animateFloat(
        initialValue = .9f,
        targetValue = .6f,
        animationSpec = infiniteRepeatable(
            animation = tween(
                durationMillis = 1500,
                easing = FastOutSlowInEasing
            ),
            repeatMode = RepeatMode.Reverse
        )
    )

    val color = Color.Magenta

    val paint = remember {
        Paint().apply {
            style = PaintingStyle.Stroke
            strokeWidth = 20f
            strokeCap = StrokeCap.Round

            this.asFrameworkPaint().apply {
                val transparent = color
                    .copy(alpha = 0f)
                    .toArgb()

                this.color = transparent
            }

            asFrameworkPaint().setShadowLayer(
                35f * phase,
                0f,
                0f,
                color
                    .copy(alpha = phase)
                    .toArgb()
            )
        }
    }


    // Path is what is used for drawing line on Canvas
    val path = remember { Path() }

    val drawModifier = Modifier
        .background(Color.Black)
        .fillMaxSize()
        .clipToBounds()
        .pointerMotionEvents(
            onDown = { pointerInputChange: PointerInputChange ->
                currentPosition = pointerInputChange.position
                motionEvent = MotionEvent.Down
                pointerInputChange.consume()
            },
            onMove = { pointerInputChange: PointerInputChange ->
                currentPosition = pointerInputChange.position
                motionEvent = MotionEvent.Move
                pointerInputChange.consume()
            },
            onUp = { pointerInputChange: PointerInputChange ->
                motionEvent = MotionEvent.Up
                pointerInputChange.consume()
            },
            delayAfterDownInMillis = 25L
        )

    Canvas(modifier = drawModifier) {
        when (motionEvent) {
            MotionEvent.Down -> {
                path.moveTo(currentPosition.x, currentPosition.y)
                previousPosition = currentPosition
            }

            MotionEvent.Move -> {
                path.quadraticTo(
                    previousPosition.x,
                    previousPosition.y,
                    (previousPosition.x + currentPosition.x) / 2,
                    (previousPosition.y + currentPosition.y) / 2

                )

                previousPosition = currentPosition
            }

            MotionEvent.Up -> {
                path.lineTo(currentPosition.x, currentPosition.y)
                currentPosition = Offset.Unspecified
                previousPosition = currentPosition
                motionEvent = MotionEvent.Idle
            }

            else -> Unit
        }

        this.drawIntoCanvas {

            it.drawPath(path, paint)

        // this is for blinking effect, remove it if not needed

            drawPath(
                color = Color.White.copy((0.7f + phase).coerceAtMost(1f)),
                path = path,
                style = Stroke(width = 4.dp.toPx(), cap = StrokeCap.Round, join = StrokeJoin.Round)
            )
        }
    }
}

This and other samples about drawing on Canvas are available in this tutorial.

发布评论

评论列表(0)

  1. 暂无评论