Jetpack Compose 从入门到入门(六)
本篇说说Compose中的Canvas。
1. Canvas
@Composable
fun Canvas(modifier: Modifier,onDraw: DrawScope.() -> Unit
) = Spacer(modifier.drawBehind(onDraw))
modifier
:这里主要作用是指定画布的大小。onDraw
就是执行具体的绘制。可以看到它提供了一个绘图环境的作用域DrawScope
,这里提供有我们经常使用的绘图api和属性,比如drawLine
、size
等。
先来一个简单的例子看看如何使用:
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
: 弧线是否过圆心
这里就不举例说明了,可以用style
、useCenter
属性自行组合尝试。
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
) {...}
clipOp
:ClipOp.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 从入门到入门(六)相关推荐
- Jetpack Compose 从开门到入门之 MenuBar桌面菜单(Desktop Menu)
MenuBar是桌面版本才有的功能.也就是传统桌面应用的菜单.效果如下: 如果你写过桌面版本的Compose,在main方法里面有一个Window,MenuBar需要定义在Window里面,在别的地方 ...
- Jetpack Compose入门详解(实时更新)
Jetpack Compose入门详解 前排提醒 前言(Compose是什么) 1.实战准备 一.优势与缺点 二.前四课 三.标准布局组件 1.Column 2.Row 3.Box 四.xml和com ...
- 告别XML,Android新声明式UI框架《Jetpack Compose入门到精通》最全开发指南
什么是Jetpack Compose? Jetpack Compose是Android的新声明式UI框架.长期以来, Android 开发人员习惯于使用带有状态视图的xml编写UI,这些状态视图通过逐 ...
- 《Jetpack Compose 从入门到实战》带你踏上 Compose 开发之旅~
写书的契机 Jetpack Compose 首次亮相于 2019 年的 Google I/O 大会,彼时的我正在为抖音客户端研发一款基于原生视图渲染的声明式 UI 框架,由于声明式开发理念在当时还过于 ...
- Android原生UI开发框架 《Jetpack Compose入门到精通》最全上手指南
前言 在去年的Google/IO大会上,亮相了一个全新的 Android 原生 UI 开发框架-Jetpack Compose, 与苹果的SwiftIUI一样,Jetpack Compose是一个声明 ...
- 重磅首发!Jetpack Compose 完全开发手册,从入门到精通!
前 言 Jetpack 架构组件 及 标准化开发模式 的确立,意味着 Android 开发已步入成熟阶段.现在的Android岗招人的时候也非常看重应试者对 Jetpack 架构组件的理解程度. 今天 ...
- Jetpack Compose 从入门到入门(三)
本篇开始介绍Jetpack Compose 中的修饰符Modifier.修饰符可以用来执行以下操作: 更改可组合项的大小.布局.行为和外观. 添加信息,如无障碍标签. 处理用户输入. 添加高级互动,如 ...
- Jetpack Compose 从入门到入门(四)
本篇开始介绍Jetpack Compose 中常用的组件.有一部分之前的文章中也出现过,今天详细说明一下. 1. Text 日常最常用的应该就是显示文字,所以有必要说一下Text控件.首先源码如下: ...
- Jetpack Compose入门
简介 Jetpack Compose是用于构建原生Android界面的新工具包.它是一种声明式的UI布局,其官方声称可简化并加快Android上的界面开发,使用更少的代码.强大的工具和直观的Kotli ...
最新文章
- 子frame获取外部元素
- ASP.NET中Cookie的使用(实战教程)
- 客户端页面不更新CSS样式或JS脚本的方法 (2018-08-17 17:33)
- C#学习小记14求助一道让我头疼的C#小题
- 《零基础》MySQL 事务(二十二)
- 2013年度开源社区年会,3W咖啡免费让你更多接触开源
- encodeURL() vs encodeRedirectURL()
- centos6.4 安装wireless驱动
- 如何解决MySQL导入大数据出现的问题
- java多线程的常用方法(以及注意事项)
- Writing Serializable Classes---定义可序列化的类
- Java观察者模式(Observer)
- vCenter资源池
- Hive指定位置增加字段及解决columns have types incompatible with the existing columns in their respective positio
- 论坛介绍 | COSCon'22 开源硬件(H)
- 个人微信支付接口,非二清,无需APP,支持H5
- tdd干扰波形_TDDLTE干扰排查指导书_V1520170219.docx
- dry的原理_4、干法蚀刻(dry etch)原理介绍
- 性能测试能力提升-基准、负载、压力、容量测试
- 波长波数转换matlab,【求助】请教红外常用波数与波长之间的转换关系...
热门文章
- 【编程基础の基础】“#define _GNU_SOURCE“或是在编译时“-D _GNU_SOURCE“代表了什么?有什么用
- Expiring XXX record(s) for XXX:120015 ms has passed since batch creation
- 在Excel中通过VBA实现不定区域的标准差计算
- django项目 网易云音乐
- 利用决策树对微信公众号文本进行分类
- MySQL-HA高可用
- SLAM发展现状研究
- 使用CSS制作斜边矩形原理分析
- 记一个跟阿里的朋友喝酒的周末-20211201
- java 操作word中表格_Java 使用Spire.Cloud.Word给Word文档添加表格