阅读本文需要一定compose基础,如果没有请移步Jetpack Compose入门详解(实时更新)
本文介绍Compose Canvas基础,介绍Canvas可组合项依赖的原理和绘制相关的内置api。
本文的写作顺序和风格参造HenCoder Android 开发进阶: 自定义 View 1-1 绘制基础
Canvas可组合项允许我们在屏幕上指定区域并在此区域上执行画布绘制。必须使用修饰符指定大小,无论是通过modifier.size修饰符指定精确大小,还是通过modifier.fillMaxSize、ColumnScope.weight等指定相对于父项的大小。如果父项包装此子项,则必须仅指定精确大小。
参数:
@Composable
fun Canvas(modifier: Modifier, onDraw: DrawScope.() -> Unit) =
Spacer(modifier.drawBehind(onDraw))
可以看到所有的Canvas可组合项都用Spacer创建了一个空白的可组合项,然后调用了Modifier.drawBehind方法。而drawBehind的作用是将onDraw中的内容绘制到修改内容后面的画布中。
以draw开头的api是Canvas绘图的一种方式
从后面衔接的单词可以看出具体我们能画个什么东西出来,下面我们举个简单例子。
例子如下:
Canvas(modifier = Modifier, onDraw = {
drawCircle(
color = Color(0xFFF44336),
radius = size.width / 4,
center = center
)
} )
注意,上例中的size和center表示Canvas 的尺寸和中心
参数解释:
那么我们只想画一个没有填充颜色,只有描边颜色的圆要怎么做呢?添加style就够了
drawCircle(
color = Color(0xFFF44336),
radius = size.width / 4,
center = center,
style = Stroke()
)
改变上例代码:
drawCircle(
color = Color(0xFFF44336),
radius = size.width / 4,
center = center,
style = Stroke(20f)
)
其实也是差不多的,示例代码如下:
drawRect(
color = Color(0xFFF44336),
size = Size(size.width/4,size.height/4),
)
drawRect(
color = Color(0xFFF44336),
size = Size(size.width/4,size.height/4),
style = Stroke(20f),
topLeft = Offset(300F, 0F)
)
参数解释:
示例代码如下:
val list: MutableList<Offset> = mutableListOf()
val offset = Offset(100f, 100f)
val offset1 = Offset(200f, 200f)
val offset3= Offset(100f, 300f)
list.add(offset)
list.add(offset1)
list.add(offset3)
drawPoints(
points = list,
pointMode = PointMode.Points,
color = Color.Black,
strokeWidth = 20f,
cap = StrokeCap.Round
)
我们重点说下pointMode
PointMode.Points 也就是上例代码使用的,会 分别绘制每个点。
如果Paint.strokeCap为strokeCap.Round,则每个点都绘制为直径为Paint.stronkeWidth的圆,并按照Paint(忽略Paint.style)的说明填充。
否则,每个点都将绘制为一个轴对齐的正方形,边长为Paint.strokeWidth,按“绘制”(忽略“绘制.样式”)所述填充
PointMode.Lines 将两个点的每个序列绘制为线段。如果点数为奇数,则忽略最后一个点。线条按“绘制”(Paint)所述进行笔划处理(忽略“绘制.样式”)。
将pointMode更改为Lines的效果
PointMode.Polygon 将整个点序列绘制为一条线。线条按“绘制”(Paint)所述进行笔划处理(忽略“绘制.样式”)。
将pointMode更改为Polygon的效果
示例代码:
drawOval(
color = Color(0xFFF44336),
size = Size(size.width/4,size.height/4),
)
和画矩形的参数是一模一样的
示例代码:
drawLine(
color = Color.Green,
start = Offset(100f,100f),
end = Offset(100f,200f),
strokeWidth = 20f
)
效果:
如果你仔细观察可以发现drawPoints的PointMode.Lines模式可以实现drawLine一样的效果,这是没有差别的,全看个人喜好。
示例代码:
drawRoundRect(
color = Color(0xFFF44336),
size = Size(size.width/4,size.height/4),
style = Stroke(20f),
topLeft = Offset(300F, 0F),
cornerRadius = CornerRadius(50f)
)
效果:
示例代码:
drawArc(
color = Color(0xFFF44336),
size = Size(size.width/2,size.height/4),
startAngle = 0f,
sweepAngle = 90f,
useCenter = true
)
将useCenter = false
drawArc(
color = Color(0xFFF44336),
size = Size(size.width/2,size.height/4),
startAngle = 0f,
sweepAngle = 90f,
useCenter = false
)
示例代码:
val path = Path()
path.moveTo(100f, 100f);
path.lineTo(200f,200f)
path.lineTo(100f,200f)
drawPath(path,color = Color(0xFFF44336) )
Path 可以描述直线、二次曲线、三次曲线、圆、椭圆、弧形、矩形、圆角矩形。把这些图形结合起来,就可以描述出很多复杂的图形。下面我就说一下具体的怎么把这些图形描述出来。
Path 有两类方法,一类是直接描述路径的,另一类是辅助的设置或计算。
import androidx.compose.foundation.Canvas
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.PointMode
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.text.drawText
import androidx.compose.ui.tooling.preview.Preview
/**
* @author zengyifeng
* @date createDate:2023-10-03
* @brief description
*/
@Preview(showBackground = true, showSystemUi = true)
@Composable
fun CanvasView() {
Canvas(modifier = Modifier, onDraw = {
drawCircle(
color = Color(0xFFF44336),
radius = size.width / 4,
center = center,
style = Stroke(20f)
)
drawOval(
color = Color(0xFFF44336),
size = Size(size.width/4,size.height/4),
)
drawRect(
color = Color(0xFFF44336),
size = Size(size.width/4,size.height/4),
style = Stroke(20f),
topLeft = Offset(300F, 0F)
)
val list: MutableList<Offset> = mutableListOf()
val offset = Offset(100f, 100f)
val offset1 = Offset(200f, 200f)
val offset3= Offset(100f, 300f)
list.add(offset)
list.add(offset1)
list.add(offset3)
drawPoints(
points = list,
pointMode = PointMode.Polygon,
color = Color.Black,
strokeWidth = 20f,
cap = StrokeCap.Round
)
drawLine(
color = Color.Green,
start = Offset(100f,100f),
end = Offset(100f,200f),
strokeWidth = 20f
)
drawRoundRect(
color = Color(0xFFF44336),
size = Size(size.width/4,size.height/4),
style = Stroke(20f),
topLeft = Offset(300F, 0F),
cornerRadius = CornerRadius(50f)
)
drawArc(
color = Color(0xFFF44336),
size = Size(size.width/2,size.height/4),
startAngle = 0f,
sweepAngle = 90f,
useCenter = false
)
val path = Path()
path.moveTo(100f, 100f);
path.lineTo(200f,200f)
path.lineTo(100f,200f)
drawPath(path,color = Color(0xFFF44336) )
})
}
本文介绍了Compose Canvas基础,包括Canvas可组合项的使用方法,以及绘制各种形状的api方法。通过本文的介绍,我们可以了解到Canvas绘制的基本原理和常用的api方法,可以为我们后续的Compose开发中提供参考。同时也要注意到不同参数的调整会对绘制结果产生不同的影响。