Canvas draws points
/** *Canvas draw points */ @Composable fun DrawPointsTest() { val points = arrayListOf( Offset(100f, 100f), Offset(300f, 300f), Offset(500f, 500f), Offset(700f, 700f), Offset(900f, 900f) ) Canvas(modifier = Modifier.size(360.dp)) { drawPoints( points = points, //Type PointMode.Points: Points PointMode.Lines: Lines PointMode.Polygon: Polygons pointMode = PointMode.Points, //color color = Color.Blue, //color gradient // brush = Brush.linearGradient( // 0.0f to Color.Red, // 0.5f to Color.Green, // 1.0f to Color.Blue // ), //width strokeWidth = 30f, //Butt indicates that the starting point and end point of the end contour of the line segment have gentle edges and no extension; //Round represents the outline of the line segment starting and ending with a semicircle; //Square means that the end of the line segment extends each outline by half the stroke width. cap = StrokeCap.Round ) } }
Use drawPoints to draw points under the Canvas component; add point coordinates with the points attribute; pointMode setting type: PointMode.Points coordinates are points.
PointMode.Lines Two coordinate points form a line segment. If there are not enough coordinates, the last coordinate point will be automatically omitted and not displayed.
PointMode.Polygon polygon, multi-coordinate point connection, is similar to drawPath for drawing paths.
The color attribute sets the color of the coordinate point.
The brush attribute sets the gradient of the coordinate point or line.
The strokeWidth property sets the width of the coordinate point or line.
cap sets whether the end of the coordinate point or line is rounded. If not set, the default is a square coordinate point, and after setting, it is a circular coordinate point. Do not set the actual points or lines.
Canvas draws lines
/** * Canvas draws lines */ @Composable fun DrawLineTest() { val start = Offset(100f, 100f) val end = Offset(900f, 900f) Canvas(modifier = Modifier.size(360.dp)) { drawLine( //line color color = Color.Red, //starting point start = start, //end point end = end, //Line width strokeWidth = 30f, //Round end of line cap = StrokeCap.Round ) } }
Use drawLine to draw a line. Except for the difference in the coordinate point attributes of the start and end starting points, other attributes are basically the same as the drawing point attributes.
Canvas draws rectangle
/** * Canvas draws rectangle (solid) */ @Composable fun DrawRectTest() { val topLeft = Offset(100f, 100f) Canvas(modifier = Modifier.size(360.dp)) { drawRect( color = Color.Red, topLeft = topLeft, size = Size(400f, 600f) ) } }
/** * Canvas draws rectangle (hollow) */ @Composable fun DrawRectStrokTest() { val topLeft = Offset(100f, 100f) val rectSize = Size(400f, 600f) Canvas(modifier = Modifier.size(360.dp)) { drawRect( color = Color.Red, topLeft = topLeft, size = rectSize, //Stroke set hollow style = Stroke( //border width width = 30f, //Used to set the processing method for connecting straight lines and curve segments on the stroke path //StrokeJoin.Miter: sharp corner StrokeJoin.Bevel: beveled corner StrokeJoin.Round: rounded corner join = StrokeJoin.Round ) ) } }
The topLeft attribute sets the top and left margin, and the size attribute sets the size of the rectangle.
The style attribute sets the rectangle style, Stroke is set to a hollow rectangle, the width attribute in Stroken sets the width of the rectangular line, and the join attribute sets the shape of the border corner.
When join is set to StrokeJoin.Bevel, the rectangular border has bevel corners like this:
Not set or set to StrokeJoin.Miter as right angle.
Canvas draws rounded rectangle
/** * Canvas draws rounded rectangle */ @Composable fun DrawRoundRectTest() { val topLeft = Offset(100f, 100f) val rectSize = Size(400f, 600f) Canvas(modifier = Modifier.size(360.dp)) { drawRoundRect( color = Color.Red, topLeft = topLeft, size = rectSize, //round corner settings cornerRadius = CornerRadius(100f), //Stroke set hollow style = Stroke( //border width width = 30f, //Used to set the processing method for connecting straight lines and curve segments on the stroke path //StrokeJoin.Miter: sharp corner StrokeJoin.Bevel: beveled corner StrokeJoin.Round: rounded corner join = StrokeJoin.Round ) ) } }
Use drawRoundRect to draw a rounded rectangle. When the width and height of the rectangle are the same and the rounded angle is set large enough, the rectangle will become a circle. Use the cornerRadius property to set the rounded corners. Just don’t set the style attribute.
Canvas draws a circle
/** * Canvas draws circle */ @Composable fun DrawCircleTest() { Canvas(modifier = Modifier.size(360.dp)) { drawCircle( color = Color.Blue, //Centered center = center, //radius of circle radius = 300f, //Hollow settings style = Stroke( width=30f ) ) } }
Although drawRoundRect can draw a circle, it needs to be set to have the same width and height of the rectangle and the rounded corners are large enough before it becomes a circle. You can set the circle directly using drawCircle. You only need to set the radius of the circle through the radius attribute.
Canvas draws ellipse
/** * Canvas draws ellipse */ @Composable fun DrawOvalTest() { val topLeft = Offset(100f, 100f) val ovalSize = Size(600f, 800f) Canvas(modifier = Modifier.size(360.dp)) { drawOval( color = Color.Blue, //starting point topLeft = topLeft, //size setting size = ovalSize, //Hollow settings style = Stroke( width=30f ) ) } }
Use drawOval to draw an ellipse. When the width and height of the ellipse are the same, the ellipse will also become a circle.
Therefore, drawOval, drawCircle, and drawRoundRect under Canvas can all set circles.
Canvas draws arc
/** * Canvas draws arc */ @Composable fun DrawAcrTest() { val ovalSize = Size(600f, 600f) Canvas(modifier = Modifier.size(360.dp)) { drawArc( color = Color.Blue, size = ovalSize, //Start angle (starting at 3 o'clock) startAngle = 0f, //scan angle sweepAngle = 100f, //center alignment useCenter = true, //Hollow settings style = Stroke( width=20f ) ) } }
Use drawArc to set the arc. You only need to set the startAngle and sweepAngle starting angles to draw a sector or arc.
When the useCenter property is set to false, an arc is drawn.
Canvas draws pictures
/** * Canvas draws pictures */ @Composable fun DrawImageTest() { val context = LocalContext.current val bitmap = BitmapFactory.decodeResource(context.resources, R.drawable.img) val image = bitmap.asImageBitmap() Canvas(modifier = Modifier.size(360.dp)) { //image - the source image to draw //srcOffset - optional offset, representing the offset of the upper left corner of the source image to be drawn, defaulting to the origin of the image //srcSize - Optional size of the source image drawn relative to srcOffset, defaults to the width and height of the image //dstOffset - Optional offset, representing the upper left offset of the destination for drawing the given image, defaults to the origin of the current translation, starting from the upper left offset of the destination for drawing the image //dstSize - Optional size of the drawing target, default is srcSize //alpha - the opacity applied to the image from 0.0f to 1.0f, representing fully transparent to fully opaque respectively //Style - specifies whether the image is filled or drawn with a rectangular stroke //colorFilter - applies a colorFilter to the image when drawing to the destination //blendMode - the blending algorithm applied to the target //filterQuality - The sampling algorithm to apply to the image when it is scaled and drawn to the destination. Default is FilterQuality. Scaling using bilinear sampling algorithm drawImage( image = image, srcOffset = IntOffset(0, 0), srcSize = IntSize(400, 400), dstOffset = IntOffset(100, 100), dstSize = IntSize(800, 800) ) } }
Use drawImage to draw pictures under Canvas.
Canvas drawing path
/** *Canvas draw path */ @Composable fun DrawPathTest() { val path = Path() path.moveTo(100f, 100f) path.lineTo(100f, 300f) path.lineTo(400f, 600f) path.lineTo(700f, 300f) path.lineTo(700f, 100f) path.lineTo(650f, 50f) path.lineTo(600f, 50f) path.lineTo(400f, 200f) path.lineTo(200f, 50f) path.lineTo(150f, 50f) // path.quadraticBezierTo(800f, 700f, 600f, 100f) // Second-order Bezier curve // path.cubicTo(700f, 200f, 800f, 400f, 100f, 100f) // Third-order Bezier curve path.close() Canvas(modifier = Modifier.size(360.dp)) { drawPath( //Path settings path = path, //Color settings color = Color.Red, //Hollow settings style = Stroke( width=10f ) ) } }
Use drawPath to draw a path under Canvas, and use the path attribute path coordinates under drawPath. The path can use the quadraticBezierTo attribute to add a second-order Bezier curve, and the cubicTo attribute to add a third-order Bezier curve.
Canvas blending mode
/** * Use blending modes */ @Composable fun DrawBlendModeTest() { Canvas(modifier = Modifier.fillMaxSize()) { //Left arm drawRoundRect( color = Color(0xFFA5CA39), topLeft = Offset(100f, 400f), size = Size(120f, 400f), //round corner settings cornerRadius = CornerRadius(100f) ) //right arm drawRoundRect( color = Color(0xFFA5CA39), topLeft = Offset(780f, 400f), size = Size(120f, 400f), //round corner settings cornerRadius = CornerRadius(100f) ) //Left tentacle drawLine( //line color color = Color(0xFFA5CA39), //starting point start = Offset(350f, 100f), //end point end = Offset(400f, 200f), //Line width strokeWidth = 20f, //Round end of line cap = StrokeCap.Round ) //Right tentacle drawLine( //line color color = Color(0xFFA5CA39), //starting point start = Offset(650f, 100f), //end point end = Offset(600f, 200f), //Line width strokeWidth = 20f, //Round end of line cap = StrokeCap.Round ) //head drawArc( color = Color(0xFFA5CA39), size = Size(500f, 500f), topLeft = Offset(250f, 150f), //Start angle startAngle = 180f, //scan angle sweepAngle = 180f, //center alignment useCenter = true ) //left eye drawPoints( points = arrayListOf( Offset(380f, 280f) ), pointMode = PointMode.Points, color = Color(0xFFFFFFFF), strokeWidth = 50f, cap = StrokeCap.Round ) //right eye drawPoints( points = arrayListOf( Offset(620f, 280f) ), pointMode = PointMode.Points, color = Color(0xFFFFFFFF), strokeWidth = 50f, cap = StrokeCap.Round ) //Body drawPath( path = Path().apply { addRoundRect( RoundRect( rect = Rect( offset = Offset(250f, 420f), size = Size(500f, 480f), ), bottomLeft = CornerRadius(100f, 100f), bottomRight = CornerRadius(100f, 100f), ) ) }, color = Color(0xFFA5CA39) ) //left leg drawPath( path = Path().apply { addRoundRect( RoundRect( rect = Rect( offset = Offset(350f, 880f), size = Size(120f, 240f), ), bottomLeft = CornerRadius(100f, 100f), bottomRight = CornerRadius(100f, 100f), ) ) }, color = Color(0xFFA5CA39) ) //right leg drawPath( path = Path().apply { addRoundRect( RoundRect( rect = Rect( offset = Offset(550f, 880f), size = Size(120f, 240f), ), bottomLeft = CornerRadius(100f, 100f), bottomRight = CornerRadius(100f, 100f), ) ) }, color = Color(0xFFA5CA39) ) } }
What I use here is drawRoundRect to draw a rounded rectangle to draw the arms, drawLine to draw a line to draw the tentacles, use drawArc to draw an arc to draw the head, use drawPoints to draw points, and drawPath to draw the eyes. The body and legs are drawn in the form of paths.
Of course, there is no unique way to draw various shapes. You are welcome to explore more simple and practical Compose drawing methods.