Jetpack Compose 从入门到入门
Posted 唯鹿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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.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
: 弧线是否过圆心
这里就不举例说明了,可以用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.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
) ...
本篇到此结束,下一篇应该就是compose的动画部分了,敬请期待~
4.参考
以上是关于Jetpack Compose 从入门到入门的主要内容,如果未能解决你的问题,请参考以下文章