Skip to Content

Graphics và Canvas trong Jetpack Compose

Compose cung cấp APIs mạnh mẽ để vẽ custom graphics, từ shapes đơn giản đến drawings phức tạp.

1. Canvas Composable

Cơ bản

@Composable fun SimpleCanvas() { Canvas(modifier = Modifier.size(200.dp)) { // DrawScope - vẽ ở đây drawRect(color = Color.Blue) } }

DrawScope properties

Canvas(modifier = Modifier.size(200.dp)) { val width = size.width // Chiều rộng canvas val height = size.height // Chiều cao canvas val center = this.center // Tâm canvas // Vẽ tại center drawCircle( color = Color.Red, radius = 50f, center = center ) }

2. Vẽ Shapes cơ bản

Rectangle

Canvas(modifier = Modifier.size(200.dp)) { // Filled rectangle drawRect(color = Color.Blue) // Rectangle với size và offset drawRect( color = Color.Red, topLeft = Offset(20f, 20f), size = Size(100f, 80f) ) // Outlined rectangle drawRect( color = Color.Green, style = Stroke(width = 4f) ) }

Circle và Oval

Canvas(modifier = Modifier.size(200.dp)) { // Circle drawCircle( color = Color.Blue, radius = 80f, center = center ) // Oval drawOval( color = Color.Red, topLeft = Offset(10f, 50f), size = Size(180f, 100f) ) }

Line

Canvas(modifier = Modifier.size(200.dp)) { drawLine( color = Color.Blue, start = Offset(0f, 0f), end = Offset(size.width, size.height), strokeWidth = 4f ) // Dashed line drawLine( color = Color.Red, start = Offset(0f, size.height), end = Offset(size.width, 0f), strokeWidth = 4f, pathEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 10f)) ) }

Arc

Canvas(modifier = Modifier.size(200.dp)) { // Arc (partial circle) drawArc( color = Color.Blue, startAngle = 0f, sweepAngle = 270f, // Vẽ 270 độ useCenter = true, // Nối với tâm thành hình quạt topLeft = Offset(20f, 20f), size = Size(160f, 160f) ) }

3. Path - Vẽ hình dạng tùy ý

Path cơ bản

Canvas(modifier = Modifier.size(200.dp)) { val path = Path().apply { moveTo(0f, size.height) // Start bottom-left lineTo(size.width / 2, 0f) // Go to top-center lineTo(size.width, size.height) // Go to bottom-right close() // Close path (tam giác) } drawPath(path, color = Color.Blue) }

Bezier curves

Canvas(modifier = Modifier.size(200.dp)) { val path = Path().apply { moveTo(0f, size.height / 2) // Quadratic Bezier (1 control point) quadraticBezierTo( x1 = size.width / 2, y1 = 0f, // Control point x2 = size.width, y2 = size.height / 2 // End point ) } drawPath( path = path, color = Color.Blue, style = Stroke(width = 4f) ) }

Cubic Bezier

Canvas(modifier = Modifier.size(200.dp)) { val path = Path().apply { moveTo(0f, size.height) // Cubic Bezier (2 control points) cubicTo( x1 = size.width * 0.25f, y1 = 0f, // Control point 1 x2 = size.width * 0.75f, y2 = size.height, // Control point 2 x3 = size.width, y3 = 0f // End point ) } drawPath( path = path, color = Color.Blue, style = Stroke(width = 4f) ) }

4. Brush - Gradients và Patterns

Linear Gradient

Canvas(modifier = Modifier.size(200.dp)) { drawRect( brush = Brush.linearGradient( colors = listOf(Color.Red, Color.Yellow, Color.Green), start = Offset.Zero, end = Offset(size.width, size.height) ) ) }

Radial Gradient

Canvas(modifier = Modifier.size(200.dp)) { drawCircle( brush = Brush.radialGradient( colors = listOf(Color.White, Color.Blue), center = center, radius = size.minDimension / 2 ) ) }

Sweep Gradient

Canvas(modifier = Modifier.size(200.dp)) { drawCircle( brush = Brush.sweepGradient( colors = listOf(Color.Red, Color.Yellow, Color.Green, Color.Blue, Color.Red), center = center ) ) }

Gradient với color stops

Canvas(modifier = Modifier.size(200.dp)) { drawRect( brush = Brush.horizontalGradient( colorStops = arrayOf( 0.0f to Color.Red, 0.3f to Color.Yellow, 1.0f to Color.Green ) ) ) }

5. Text trên Canvas

Canvas(modifier = Modifier.size(200.dp)) { drawContext.canvas.nativeCanvas.apply { drawText( "Hello Canvas", center.x, center.y, android.graphics.Paint().apply { textSize = 40f color = android.graphics.Color.BLUE textAlign = android.graphics.Paint.Align.CENTER } ) } }

Với TextMeasurer (Compose cách)

@Composable fun TextOnCanvas() { val textMeasurer = rememberTextMeasurer() Canvas(modifier = Modifier.size(200.dp)) { drawText( textMeasurer = textMeasurer, text = "Hello Compose", topLeft = Offset(10f, 10f), style = TextStyle( fontSize = 20.sp, color = Color.Blue ) ) } }

6. Transformations

Scale, Rotate, Translate

Canvas(modifier = Modifier.size(200.dp)) { withTransform({ translate(left = 50f, top = 50f) rotate(degrees = 45f, pivot = Offset(50f, 50f)) scale(scaleX = 1.5f, scaleY = 1.5f, pivot = Offset(50f, 50f)) }) { drawRect( color = Color.Blue, topLeft = Offset.Zero, size = Size(100f, 100f) ) } }

inset

Canvas(modifier = Modifier.size(200.dp)) { // Draw full size drawRect(color = Color.LightGray) // Draw with inset inset(20f, 20f, 20f, 20f) { drawRect(color = Color.Blue) } }

7. Blend Modes

Canvas(modifier = Modifier.size(200.dp)) { drawCircle( color = Color.Red, radius = 80f, center = Offset(80f, 100f) ) drawCircle( color = Color.Blue, radius = 80f, center = Offset(120f, 100f), blendMode = BlendMode.Multiply // Blend với circle phía dưới ) }

Các BlendMode phổ biến

ModeMô tả
SrcOverDefault - vẽ đè lên
MultiplyNhân màu
ScreenSáng hơn
OverlayKết hợp Multiply và Screen
DifferenceHiệu màu
ClearXóa vùng

8. drawWithContent và drawBehind

drawBehind - Vẽ phía sau content

@Composable fun CardWithShadow(content: @Composable () -> Unit) { Box( modifier = Modifier .drawBehind { // Vẽ shadow phía sau drawRoundRect( color = Color.Gray.copy(alpha = 0.3f), topLeft = Offset(4.dp.toPx(), 4.dp.toPx()), cornerRadius = CornerRadius(8.dp.toPx()) ) } .background(Color.White, RoundedCornerShape(8.dp)) ) { content() } }

drawWithContent - Vẽ trước hoặc sau content

@Composable fun GradientOverlay() { Box( modifier = Modifier .size(200.dp) .drawWithContent { drawContent() // Vẽ content trước // Vẽ gradient overlay lên trên drawRect( brush = Brush.verticalGradient( colors = listOf(Color.Transparent, Color.Black.copy(alpha = 0.5f)) ) ) } ) { Image( painter = painterResource(R.drawable.image), contentDescription = null ) } }

9. Custom Progress Indicator

@Composable fun CircularProgress( progress: Float, // 0 to 1 modifier: Modifier = Modifier ) { Canvas(modifier = modifier.size(100.dp)) { val strokeWidth = 8.dp.toPx() val diameter = size.minDimension - strokeWidth // Background circle drawCircle( color = Color.LightGray, radius = diameter / 2, center = center, style = Stroke(width = strokeWidth) ) // Progress arc drawArc( color = Color.Blue, startAngle = -90f, sweepAngle = progress * 360f, useCenter = false, topLeft = Offset(strokeWidth / 2, strokeWidth / 2), size = Size(diameter, diameter), style = Stroke( width = strokeWidth, cap = StrokeCap.Round ) ) } }

10. Animated Graphics

@Composable fun AnimatedWave() { val infiniteTransition = rememberInfiniteTransition() val phase by infiniteTransition.animateFloat( initialValue = 0f, targetValue = 2 * Math.PI.toFloat(), animationSpec = infiniteRepeatable( animation = tween(2000, easing = LinearEasing) ) ) Canvas(modifier = Modifier.fillMaxWidth().height(100.dp)) { val path = Path() path.moveTo(0f, size.height / 2) for (x in 0..size.width.toInt()) { val y = (size.height / 2) + (30 * sin((x * 0.02) + phase)).toFloat() path.lineTo(x.toFloat(), y) } drawPath( path = path, color = Color.Blue, style = Stroke(width = 4f) ) } }

📝 Tóm tắt

DrawingFunction
RectangledrawRect()
CircledrawCircle()
OvaldrawOval()
LinedrawLine()
ArcdrawArc()
PathdrawPath()
ImagedrawImage()
TextdrawText()

Modifiers cho drawing

ModifierMục đích
drawBehindVẽ phía sau content
drawWithContentVẽ trước/sau content
drawWithCacheCache drawing objects
Last updated on