亲宝软件园·资讯

展开

Jetpack Compose Canvas绘制超详细介绍

唯鹿 人气:1

1. Canvas

@Composable
fun Canvas(
	modifier: Modifier,
	onDraw: DrawScope.() -> Unit
) = Spacer(modifier.drawBehind(onDraw))

先来一个简单的例子看看如何使用:

Canvas(modifier = Modifier.fillMaxSize()) {
    val canvasWidth = size.width
    val canvasHeight = size.height
    drawLine(
        start = Offset(x = canvasWidth, y = 0f),
        end = Offset(x = 0f, y = canvasHeight),
        color = Color.Blue
    )
}

画一条线,开始和结束位置分别是画布的右上角和左下角。效果如下:

2. 绘制方法

1. drawLine

drawLine在上面的例子中简单说明了,当然它不止这些功能。

	fun drawLine(
        color: Color, //或 brush: Brush,
        start: Offset,
        end: Offset,
        strokeWidth: Float = Stroke.HairlineWidth,
        cap: StrokeCap = Stroke.DefaultCap,
        pathEffect: PathEffect? = null,
        /*FloatRange(from = 0.0, to = 1.0)*/
        alpha: Float = 1.0f,
        colorFilter: ColorFilter? = null,
        blendMode: BlendMode = DefaultBlendMode
    )

pathEffect是线段的效果,比如虚线这种就是使用PathEffect.dashPathEffect(intervals: FloatArray, phase: Float = 0f) ,举一个例子:

PathEffect.dashPathEffect(floatArrayOf(20f, 10f), 10f)

intervals中的20f表示虚线的宽度,10f是间隔宽度。phase的10f表示初始的偏移距离。所以一开始偏移10f,就会导致第一段的线段被"裁剪"10f,具体效果如下图:

2. drawRect

绘制矩形方法,属性与drawLine大同小异,下面说一些不同点。

	fun drawRect(
        color: Color,
        topLeft: Offset = Offset.Zero,
        size: Size = this.size.offsetSize(topLeft),
        /*@FloatRange(from = 0.0, to = 1.0)*/
        alpha: Float = 1.0f,
        style: DrawStyle = Fill,
        colorFilter: ColorFilter? = null,
        blendMode: BlendMode = DefaultBlendMode
    )

3. drawRoundRect

绘制圆角矩形基本与矩形一致,只是多了一个设置圆角大小的参数drawRoundRect,这里就不多说明了。

4. drawImage

绘制图片方法

	fun drawImage(
        image: ImageBitmap,
        srcOffset: IntOffset = IntOffset.Zero,
        srcSize: IntSize = IntSize(image.width, image.height),
        dstOffset: IntOffset = IntOffset.Zero,
        dstSize: IntSize = srcSize,
        /*@FloatRange(from = 0.0, to = 1.0)*/
        alpha: Float = 1.0f,
        style: DrawStyle = Fill,
        colorFilter: ColorFilter? = null,
        blendMode: BlendMode = DefaultBlendMode
    )

下面的代码是绘制一张图片的右下角区域,相对画布偏移50 * 50,绘制的大小是200 * 200。

 	val imageBitmap = ImageBitmap.imageResource(id = R.mipmap.ic_launcher)
    Canvas(modifier = Modifier.fillMaxSize()) {
        drawImage(
            image = imageBitmap,
            srcOffset = IntOffset(imageBitmap.width / 2,imageBitmap.height / 2),
            srcSize = IntSize(imageBitmap.width, imageBitmap.height),
            dstOffset = IntOffset(50,50),
            dstSize = IntSize(200,200)
        )
    }

效果如下:

5. drawCircle

绘制圆形方法

	fun drawCircle(
        color: Color,
        radius: Float = size.minDimension / 2.0f,
        center: Offset = this.center,
        /*@FloatRange(from = 0.0, to = 1.0)*/
        alpha: Float = 1.0f,
        style: DrawStyle = Fill,
        colorFilter: ColorFilter? = null,
        blendMode: BlendMode = DefaultBlendMode
    )

6. drawArc

drawArc可以用来绘制弧形或是扇形

	fun drawArc(
        color: Color,
        startAngle: Float,
        sweepAngle: Float,
        useCenter: Boolean,
        topLeft: Offset = Offset.Zero,
        size: Size = this.size.offsetSize(topLeft),
        /*@FloatRange(from = 0.0, to = 1.0)*/
        alpha: Float = 1.0f,
        style: DrawStyle = Fill,
        colorFilter: ColorFilter? = null,
        blendMode: BlendMode = DefaultBlendMode
    )

这里就不举例说明了,可以用styleuseCenter属性自行组合尝试。

7. drawPath

绘制路径方法

	fun drawPath(
        path: Path,
        color: Color,
        /*@FloatRange(from = 0.0, to = 1.0)*/
        alpha: Float = 1.0f,
        style: DrawStyle = Fill,
        colorFilter: ColorFilter? = null,
        blendMode: BlendMode = DefaultBlendMode
    )

其实和Android中的path使用一样,围绕着moveTo、lineTo、close这些方法,也就不详细说明了。

8. drawPoints

绘制点的方法

	fun drawPoints(
        points: List<Offset>,
        pointMode: PointMode,
        color: Color,
        strokeWidth: Float = Stroke.HairlineWidth,
        cap: StrokeCap = StrokeCap.Butt,
        pathEffect: PathEffect? = null,
        /*@FloatRange(from = 0.0, to = 1.0)*/
        alpha: Float = 1.0f,
        colorFilter: ColorFilter? = null,
        blendMode: BlendMode = DefaultBlendMode
    )

最后还有一个绘制椭圆方法drawOval,用法大同小异,就不说明了。

3. DrawScope拓展方法

1. inset

同时从左到上转换DrawScope坐标空间,并修改当前绘制区域的尺寸。

inline fun DrawScope.inset(
    left: Float,
    top: Float,
    right: Float,
    bottom: Float,
    block: DrawScope.() -> Unit
) {...}

inset有点像是在原有的画布上,嵌入了一个"新"的画布,设置的left,top就是相应的padding。

	Canvas(modifier = Modifier.fillMaxSize()){
        drawRect(
            color = Color.Blue,
        )
        inset(100f, 100f, 100f, 100f) {
            drawRect(
                color = Color.Red,
            )
        }
    }

2. translate

平移绘制区域

inline fun DrawScope.translate(
    left: Float = 0.0f,
    top: Float = 0.0f,
    block: DrawScope.() -> Unit
) {...}

只需要设置left、top方向移动的距离即可。

3. rotate与rotateRad

旋转绘制区域

inline fun DrawScope.rotate(
    degrees: Float,
    pivot: Offset = center,
    block: DrawScope.() -> Unit
) {...}

inline fun DrawScope.rotateRad(
    radians: Float,
    pivot: Offset = center,
    block: DrawScope.() -> Unit
) {...}

4. scale

缩放绘制区域。

inline fun DrawScope.scale(
    scaleX: Float,
    scaleY: Float,
    pivot: Offset = center,
    block: DrawScope.() -> Unit
) {...}

指定x、y方向上的缩放倍数即可。

5. clipRect

裁剪给定的矩形区域

inline fun DrawScope.clipRect(
    left: Float = 0.0f,
    top: Float = 0.0f,
    right: Float = size.width,
    bottom: Float = size.height,
    clipOp: ClipOp = ClipOp.Intersect,
    block: DrawScope.() -> Unit
) {...}

看个简单的例子,便于你的理解:

	Canvas(modifier = Modifier.fillMaxSize()){
        drawRect(
            color = Color.Blue,
        )
        clipRect(200f, 200f, clipOp = ClipOp.Intersect) {
            drawRect(
                color = Color.Yellow,
            )
        }
    }

左边是ClipOp.Intersect,右边是ClipOp.Difference

clipPath同理。

6. drawIntoCanvas

可以直接调用底层Canvas绘制的方法。我们用它实现一开始的drawLine例子,画一条对角线:

	Canvas(modifier = Modifier.fillMaxSize()) {
        val canvasWidth = size.width
        val canvasHeight = size.height
        drawIntoCanvas {
            val paint = Paint()
            paint.color = Color.Blue
            paint.strokeWidth = 1f
            it.drawLine(
                p1 = Offset(canvasWidth,0f),
                p2 = Offset(0f,canvasHeight),
                paint = paint
            )
        }
    }

其中drawLine方法,并不是一开始DrawScope中的drawLine:

actual typealias NativeCanvas = android.graphics.Canvas
private val EmptyCanvas = android.graphics.Canvas()
@PublishedApi internal class AndroidCanvas() : Canvas {
    @PublishedApi internal var internalCanvas: NativeCanvas = EmptyCanvas
	override fun drawLine(p1: Offset, p2: Offset, paint: Paint) {
        internalCanvas.drawLine(
            p1.x,
            p1.y,
            p2.x,
            p2.y,
            paint.asFrameworkPaint()
        )
    }
}

可以看到最终调用了Android的Canvas api。

7. withTransform

执行1个或多个转换。也就是上面平移旋转这些可以一块执行。

inline fun DrawScope.withTransform(
    transformBlock: DrawTransform.() -> Unit,
    drawBlock: DrawScope.() -> Unit
) {...}

4.参考

Compose 中的图形

Jetpack Compose 绘制 Canvas

加载全部内容

相关教程
猜你喜欢
用户评论