Jetpack Compose中的Canvas

Posted 川峰

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Jetpack Compose中的Canvas相关的知识,希望对你有一定的参考价值。

Jetpack Compose中的Canvas API 使用起来感觉比传统View中的要简单一些,因为它不需要画笔Paint和画布分开来,大多数直接就是一个函数搞定,当然也有一些限制。

Compose 直接提供了一个叫 CanvasComposable 组件,可以在任何 Composable 组件中直接使用,在 CanvasDrawScope作用域中就可以使用其提供的各种绘制Api进行绘制了。这比传统View要方便的多,传统View中,你只能继承一个View控件,才有机会覆写其onDraw()方法。

基本图形绘制

常用的API一览表:

API描述
drawLine绘制一条线
drawRect绘制一个矩形
drawImage绘制一张图片
drawRoundRect绘制一个圆角矩形
drawCircle绘制一个圆
drawOval绘制一个椭圆
drawArc绘制一条弧线
drawPath绘制一条路径
drawPoints绘制一些点

这些基本图形的绘制比较简单,基本上尝试一下就知道如何使用了。Compose中的Canvas坐标体系跟传统View一样,也是也左上角为坐标原点的,因此如果是设置偏移量都是针对Canvas左上角而言的。

drawLine

@Composable
fun DrawLineExample() 
    TutorialText2(text = "strokeWidth")
    Canvas(modifier = canvasModifier) 
        drawLine(
            start = Offset(x = 100f, y = 30f),
            end = Offset(x = size.width - 100f, y = 30f),
            color = Color.Red,
        )

        drawLine(
            start = Offset(x = 100f, y = 70f),
            end = Offset(x = size.width - 100f, y = 70f),
            color = Color.Red,
            strokeWidth = 5f
        )

        drawLine(
            start = Offset(x = 100f, y = 110f),
            end = Offset(x = size.width - 100f, y = 110f),
            color = Color.Red,
            strokeWidth = 10f
        )
    

    Spacer(modifier = Modifier.height(10.dp))
    TutorialText2(text = "StrokeCap")
    Canvas(modifier = canvasModifier) 

        drawLine(
            cap = StrokeCap.Round,
            start = Offset(x = 100f, y = 30f),
            end = Offset(x = size.width - 100f, y = 30f),
            color = Color.Red,
            strokeWidth = 20f
        )

        drawLine(
            cap = StrokeCap.Butt,
            start = Offset(x = 100f, y = 70f),
            end = Offset(x = size.width - 100f, y = 70f),
            color = Color.Red,
            strokeWidth = 20f
        )

        drawLine(
            cap = StrokeCap.Square,
            start = Offset(x = 100f, y = 110f),
            end = Offset(x = size.width - 100f, y = 110f),
            color = Color.Red,
            strokeWidth = 20f
        )
    

    Spacer(modifier = Modifier.height(10.dp))
    TutorialText2(text = "Brush")
    Canvas(modifier = canvasModifier) 

        drawLine(
            brush = Brush.linearGradient(
                colors = listOf(Color.Red, Color.Green)
            ),
            start = Offset(x = 100f, y = 30f),
            end = Offset(x = size.width - 100f, y = 30f),
            strokeWidth = 20f,
        )

        drawLine(
            brush = Brush.radialGradient(
                colors = listOf(Color.Red, Color.Green, Color.Blue)
            ),
            start = Offset(x = 100f, y = 70f),
            end = Offset(x = size.width - 100f, y = 70f),
            strokeWidth = 20f,
        )

        drawLine(
            brush = Brush.sweepGradient(
                colors = listOf(Color.Red, Color.Green, Color.Blue)
            ),
            start = Offset(x = 100f, y = 110f),
            end = Offset(x = size.width - 100f, y = 110f),
            strokeWidth = 20f,
        )
    

    Spacer(modifier = Modifier.height(10.dp))
    TutorialText2(text = "PathEffect")
    Canvas(
        modifier = Modifier
            .padding(8.dp)
            .shadow(1.dp)
            .background(Color.White)
            .fillMaxWidth()
            .height(120.dp)
    ) 

        drawLine(
            pathEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 10f)),
            start = Offset(x = 100f, y = 30f),
            end = Offset(x = size.width - 100f, y = 30f),
            color = Color.Red,
            strokeWidth = 10f
        )


        drawLine(
            pathEffect = PathEffect.dashPathEffect(floatArrayOf(40f, 10f)),
            start = Offset(x = 100f, y = 70f),
            end = Offset(x = size.width - 100f, y = 70f),
            color = Color.Red,
            strokeWidth = 10f
        )


        drawLine(
            pathEffect = PathEffect.dashPathEffect(floatArrayOf(70f, 40f)),
            start = Offset(x = 100f, y = 110f),
            end = Offset(x = size.width - 100f, y = 110f),
            cap = StrokeCap.Round,
            color = Color.Red,
            strokeWidth = 15f
        )

        val path = Path().apply 
            moveTo(10f, 0f)
            lineTo(20f, 10f)
            lineTo(10f, 20f)
            lineTo(0f, 10f)
        

        drawLine(
            pathEffect = PathEffect.stampedPathEffect(
                shape = path,
                advance = 30f,
                phase = 30f,
                style = StampedPathEffectStyle.Rotate
            ),
            start = Offset(x = 100f, y = 150f),
            end = Offset(x = size.width - 100f, y = 150f),
            color = Color.Green,
            strokeWidth = 10f
        )

        drawLine(
            pathEffect = PathEffect.stampedPathEffect(
                shape = path,
                advance = 30f,
                phase = 10f,
                style = StampedPathEffectStyle.Morph
            ),
            start = Offset(x = 100f, y = 190f),
            end = Offset(x = size.width - 100f, y = 190f),
            color = Color.Green,
            strokeWidth = 10f
        )
    
 

drawCircle & drawOval

@Composable
fun DrawCircleExample() 
    TutorialText2(text = "Oval and Circle")
    Canvas(modifier = canvasModifier2) 

        val canvasWidth = size.width
        val canvasHeight = size.height
        val radius = canvasHeight / 2

        drawOval(
            color = Color.Blue,
            topLeft = Offset.Zero,
            size = Size(1.2f * canvasHeight, canvasHeight)
        )
        drawOval(
            color = Color.Green,
            topLeft = Offset(1.5f * canvasHeight, 0f),
            size = Size(canvasHeight / 1.5f, canvasHeight)
        )
        drawCircle(
            Color.Red,
            center = Offset(canvasWidth - 2 * radius, canvasHeight / 2),
            radius = radius * 0.8f,
        )
    

    Spacer(modifier = Modifier.height(10.dp))
    TutorialText2(text = "DrawStyle")

    Canvas(modifier = canvasModifier2) 
        val canvasWidth = size.width
        val canvasHeight = size.height
        val radius = canvasHeight / 2
        val space = (canvasWidth - 6 * radius) / 4

        drawCircle(
            color = Color.Red,
            radius = radius,
            center = Offset(space + radius, canvasHeight / 2),
            style = Stroke(width = 5.dp.toPx())
        )

        drawCircle(
            color = Color.Red,
            radius = radius,
            center = Offset(2 * space + 3 * radius, canvasHeight / 2),
            style = Stroke(
                width = 5.dp.toPx(),
                join = StrokeJoin.Round,
                cap = StrokeCap.Round,
                pathEffect = PathEffect.dashPathEffect(floatArrayOf(20f, 20f))
            )
        )

        val path = Path().apply 
            moveTo(10f, 0f)
            lineTo(20f, 10f)
            lineTo(10f, 20f)
            lineTo(0f, 10f)
        

        val pathEffect = PathEffect.stampedPathEffect(
            shape = path,
            advance = 20f,
            phase = 20f,
            style = StampedPathEffectStyle.Morph
        )

        drawCircle(
            color = Color.Red,
            radius = radius,
            center = Offset(canvasWidth - space - radius, canvasHeight / 2),
            style = Stroke(
                width = 5.dp.toPx(),
                join = StrokeJoin.Round,
                cap = StrokeCap.Round,
                pathEffect = pathEffect
            )
        )
    

    Spacer(modifier = Modifier.height(10.dp))
    TutorialText2(text = "Brush")
    Canvas(modifier = canvasModifier2) 
        val canvasWidth = size.width
        val canvasHeight = size.height
        val radius = canvasHeight / 2
        val space = (canvasWidth - 6 * radius) / 4

        drawCircle(
            brush = Brush.linearGradient(
                colors = listOf(Color.Red, Color.Green),
                start = Offset(radius * .3f, radius * .1f),
                end = Offset(radius * 2f, radius * 2f)
            ),
            radius = radius,
            center = Offset(space + radius, canvasHeight / 2),
        )

        drawCircle(
            brush = Brush.radialGradient(
                colors = listOf(Color.Red, Color.Green)
            ),
            radius = radius,
            center = Offset(2 * space + 3 * radius, canvasHeight / 2),
        )

        drawCircle(
            brush = Brush.verticalGradient(
                colors = listOf(
                    Color.Red,
                    Color.Green,
                    Color.Yellow,
                    Color.Blue,
                    Color.Cyan,
                    Color.Magenta
                ),
            ),
            radius = radius,
            center = Offset(canvasWidth - space - radius, canvasHeight / 2)
        )
    
    Spacer(modifier = Modifier.height(10.dp))
    Canvas(modifier = canvasModifier2) 
        val canvasWidth = size.width
        val canvasHeight = size.height
        val radius = canvasHeight / 2
        val space = (canvasWidth - 6 * radius) / 4

        drawCircle(
            brush = Brush.sweepGradient(
                colors = listOf(
                    Color.Green,
                    Color.Red,
                    Color.Blue
                ),
                center = Offset(space + radius, canvasHeight / 2),
            ),
            radius = radius,
            center = Offset(space + radius, canvasHeight / 2),
        )

        drawCircle(
            brush = Brush.sweepGradient(
                colors = listOf(
                    Color.Green,
                    Color.Cyan,
                    Color.Red,
                    Color.Blue,
                    Color.Yellow,
                    Color.Magenta,
                ),
                // Offset for this gradient is not at center, a little bit left of center
                center = Offset(2 * space + 2.7f * radius, canvasHeight / 2),
            ),
            radius = radius,
            center = Offset(2 * space + 3 * radius, canvasHeight / 2),
        )


        drawCircle(
            brush = Brush.sweepGradient(
                colors = gradientColors,
                center = Offset(canvasWidth - space - radius, canvasHeight / 2),
            ),
            radius = radius,
            center = Offset(canvasWidth - space - radius, canvasHeight / 2)
        )
    

drawRect

@Composable
private fun DrawRectangleExample() 
    Spacer(modifier = Modifier.height(10.dp))
    TutorialText2(text = "Rectangle")
    Canvas(modifier = canvasModifier2) 
        val canvasWidth = size.width
        val canvasHeight = size.height
        val space = 60f
        val rectHeight = canvasHeight / 2
        val rectWidth = (canvasWidth - 4 * space) / 3

        drawRect(
            color = Color.Blue,
            topLeft = Offset(space, rectHeight / 2),
            size = Size(rectWidth, rectHeight)
        )

        drawRect(
            color = Color.Green,
            topLeft = Offset(2 * space + rectWidth, rectHeight / 2),
            size = Size(rectWidth, rectHeight),
            sty

以上是关于Jetpack Compose中的Canvas的主要内容,如果未能解决你的问题,请参考以下文章

Jetpack Compose 从入门到入门

Jetpack Compose 从入门到入门

Jetpack Compose 从入门到入门

Jetpack Compose - Canvas之BlendMode

Jetpack Compose 自定义绘制

使用 Jetpack Compose 完成自定义绘制