本篇说说Compose中的Canvas。

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.widthval canvasHeight = size.heightdrawLine(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.widthval canvasHeight = size.heightdrawIntoCanvas {val paint = Paint()paint.color = Color.Bluepaint.strokeWidth = 1fit.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 = EmptyCanvasoverride 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
) {...}

本篇到此结束,下一篇应该就是compose的动画部分了,敬请期待~

4.参考

  • Compose 中的图形
  • Jetpack Compose 绘制 Canvas,DrawScope, 以及Modifier.drawWithContent,BlendMode讲解

Jetpack Compose 从入门到入门(六)相关推荐

  1. Jetpack Compose 从开门到入门之 MenuBar桌面菜单(Desktop Menu)

    MenuBar是桌面版本才有的功能.也就是传统桌面应用的菜单.效果如下: 如果你写过桌面版本的Compose,在main方法里面有一个Window,MenuBar需要定义在Window里面,在别的地方 ...

  2. Jetpack Compose入门详解(实时更新)

    Jetpack Compose入门详解 前排提醒 前言(Compose是什么) 1.实战准备 一.优势与缺点 二.前四课 三.标准布局组件 1.Column 2.Row 3.Box 四.xml和com ...

  3. 告别XML,Android新声明式UI框架《Jetpack Compose入门到精通》最全开发指南

    什么是Jetpack Compose? Jetpack Compose是Android的新声明式UI框架.长期以来, Android 开发人员习惯于使用带有状态视图的xml编写UI,这些状态视图通过逐 ...

  4. 《Jetpack Compose 从入门到实战》带你踏上 Compose 开发之旅~

    写书的契机 Jetpack Compose 首次亮相于 2019 年的 Google I/O 大会,彼时的我正在为抖音客户端研发一款基于原生视图渲染的声明式 UI 框架,由于声明式开发理念在当时还过于 ...

  5. Android原生UI开发框架 《Jetpack Compose入门到精通》最全上手指南

    前言 在去年的Google/IO大会上,亮相了一个全新的 Android 原生 UI 开发框架-Jetpack Compose, 与苹果的SwiftIUI一样,Jetpack Compose是一个声明 ...

  6. 重磅首发!Jetpack Compose 完全开发手册,从入门到精通!

    前 言 Jetpack 架构组件 及 标准化开发模式 的确立,意味着 Android 开发已步入成熟阶段.现在的Android岗招人的时候也非常看重应试者对 Jetpack 架构组件的理解程度. 今天 ...

  7. Jetpack Compose 从入门到入门(三)

    本篇开始介绍Jetpack Compose 中的修饰符Modifier.修饰符可以用来执行以下操作: 更改可组合项的大小.布局.行为和外观. 添加信息,如无障碍标签. 处理用户输入. 添加高级互动,如 ...

  8. Jetpack Compose 从入门到入门(四)

    本篇开始介绍Jetpack Compose 中常用的组件.有一部分之前的文章中也出现过,今天详细说明一下. 1. Text 日常最常用的应该就是显示文字,所以有必要说一下Text控件.首先源码如下: ...

  9. Jetpack Compose入门

    简介 Jetpack Compose是用于构建原生Android界面的新工具包.它是一种声明式的UI布局,其官方声称可简化并加快Android上的界面开发,使用更少的代码.强大的工具和直观的Kotli ...

最新文章

  1. 子frame获取外部元素
  2. ASP.NET中Cookie的使用(实战教程)
  3. 客户端页面不更新CSS样式或JS脚本的方法 (2018-08-17 17:33)
  4. C#学习小记14求助一道让我头疼的C#小题
  5. 《零基础》MySQL 事务(二十二)
  6. 2013年度开源社区年会,3W咖啡免费让你更多接触开源
  7. encodeURL() vs encodeRedirectURL()
  8. centos6.4 安装wireless驱动
  9. 如何解决MySQL导入大数据出现的问题
  10. java多线程的常用方法(以及注意事项)
  11. Writing Serializable Classes---定义可序列化的类
  12. Java观察者模式(Observer)
  13. vCenter资源池
  14. Hive指定位置增加字段及解决columns have types incompatible with the existing columns in their respective positio
  15. 论坛介绍 | COSCon'22 开源硬件(H)
  16. 个人微信支付接口,非二清,无需APP,支持H5
  17. tdd干扰波形_TDDLTE干扰排查指导书_V1520170219.docx
  18. dry的原理_4、干法蚀刻(dry etch)原理介绍
  19. 性能测试能力提升-基准、负载、压力、容量测试
  20. 波长波数转换matlab,【求助】请教红外常用波数与波长之间的转换关系...

热门文章

  1. 【编程基础の基础】“#define _GNU_SOURCE“或是在编译时“-D _GNU_SOURCE“代表了什么?有什么用
  2. Expiring XXX record(s) for XXX:120015 ms has passed since batch creation
  3. 在Excel中通过VBA实现不定区域的标准差计算
  4. django项目 网易云音乐
  5. 利用决策树对微信公众号文本进行分类
  6. MySQL-HA高可用
  7. SLAM发展现状研究
  8. 使用CSS制作斜边矩形原理分析
  9. 记一个跟阿里的朋友喝酒的周末-20211201
  10. java 操作word中表格_Java 使用Spire.Cloud.Word给Word文档添加表格