欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > > 内容正文

Jetpack Compose Canvas绘制超详细介绍,

来源: 开发者 投稿于  被查看 46057 次 评论:75

Jetpack Compose Canvas绘制超详细介绍,


目录
  • 1. Canvas
  • 2. 绘制方法
    • 1. drawLine
    • 2. drawRect
    • 3. drawRoundRect
    • 4. drawImage
    • 5. drawCircle
    • 6. drawArc
    • 7. drawPath
    • 8. drawPoints
  • 3. DrawScope拓展方法
    • 1. inset
    • 2. translate
    • 3. rotate与rotateRad
    • 4. scale
    • 5. clipRect
    • 6. drawIntoCanvas
    • 7. withTransform
  • 4.参考

    1. Canvas

    @Composable
    fun Canvas(
    	modifier: Modifier,
    	onDraw: DrawScope.() -> Unit
    ) = Spacer(modifier.drawBehind(onDraw))
    
    • modifier:这里主要作用是指定画布的大小。
    • onDraw就是执行具体的绘制。可以看到它提供了一个绘图环境的作用域 DrawScope,这里提供有我们经常使用的绘图api和属性,比如drawLinesize等。

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

    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
        )
    • 指定线的颜色用color
    • 渐变色可以使用brush,本系列第三篇有说明。
    • strokeWidth 是线的宽度,默认是1px。
    • cap是线头的形状,默认是StrokeCap.Butt平头。还有StrokeCap.Round圆头,StrokeCap.Square方头。这部分和Android中的Paint是一样的。平头和方头的不同在于是否延伸出来的部分。

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

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

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

    • alpha 是线段的透明度。
    • colorFilter是颜色过滤器,本系列第四篇有说明,这里就不重复介绍了。
    • blendMode:混合模式。这个不在本篇的范围内,后面有机会我会详细说一下。有兴趣可以先看看文末的参考文章。

    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
        )
    
    • topLeft是用来指定左上角的偏移量,如果没有指定那么默认从当前画布左上角开始。
    • size用来指定矩形大小,如果没有指定那么默认就是当前画布的大小。
    • style是指实心还是空心。默认Fill实心,Stroke空心。

    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
        )
    
    • image:需要绘制的图片,具体可以使用ImageBitmap.imageResource(id = R.drawable.xxx)方法获取。
    • srcOffset:需要绘制图片的左上角偏移量,默认为图像的原点。
    • srcSize: 图片相对于srcOffset的尺寸,默认为图像的宽高。
    • dstOffset: 绘制图片的相对左上角的偏移量,这默认为图像的原点。
    • dstSize:绘制图片的大小,默认为srcSize

    下面的代码是绘制一张图片的右下角区域,相对画布偏移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
        )
    • radius:圆的半径大小。
    • center:圆心位置。

    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
        )
    
    • startAngle: 开始角度
    • sweepAngle: 弧线扫过的角度
    • useCenter: 弧线是否过圆心

    这里就不举例说明了,可以用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
        )
    
    • points:点的偏移位置
    • pointMode:点的绘制模式,PointMode.Points分别画出每个点。PointMode.Lines 每两个点画成一条线段。 如果点数是奇数,则忽略最后一个点。PointMode.Polygon 连接所有的点。

    最后还有一个绘制椭圆方法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
    ) {...}
    
    • degrees是旋转了多少角度。
    • radians是旋转了多少弧度。
    • pivot 是旋转的中心点,默认是中心。

    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
    ) {...}
    
    • clipOpClipOp.Intersect是裁剪矩形的里面,ClipOp.Difference是裁剪矩形的外面。

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

    	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

    到此这篇关于Jetpack Compose Canvas绘制超详细介绍的文章就介绍到这了,更多相关Jetpack Compose Canvas内容请搜索3672js教程以前的文章或继续浏览下面的相关文章希望大家以后多多支持3672js教程!

    您可能感兴趣的文章:
    • Jetpack Compose常用组件详细介绍
    • Jetpack Compose状态专篇精讲
    • Jetpack Compose修饰符专项精讲
    • Jetpack Compose入门基础全面精讲
    • Jetpack Compose自定义动画与Animatable详解

    用户评论