Canvas in Jetpack Compose Android

Canvas in Jetpack Compose

Canvas in Jetpack Compose


Canvas in Jetpack Compose is used for custom drawing and graphics rendering that goes beyond the standard UI components. 
It allows developers to create unique shapes, animations, and effects that aren’t possible with built-in composables.

Canvas in Jetpack Compose provides limitless possibilities for custom UI designs, animations, and interactive effects. By mastering Canvas, you can create unique and dynamic experiences in your Android apps.


Jetpack Compose provides a powerful Canvas API that allows developers to create custom drawings, animations, and effects. 
With Canvas, you can draw shapes, paths, text, and images, giving you full control over UI elements.

Why Use Canvas in Jetpack Compose?

  1. ✅ Full Control – Draw anything pixel-perfect.
  2. ✅ Lightweight & Efficient – Avoids unnecessary recompositions.
  3. ✅ Custom Animations – Beyond standard UI animations.
  4. ✅ Interactive UI – Gestures, touch-based interactions.
  5. ✅ Optimized Performance – Hardware-accelerated rendering.

How to Position an object on Screen in Jetpack Compose Canvas

The x and y coordinates determine where the object is drawn.
Position Offset Formula
Center Offset(size.width / 2, size.height / 2)
Top-Left Offset(radius, radius)
Top-Right Offset(size.width - radius, radius)
Bottom-Left Offset(radius, size.height - radius)
Bottom-Right Offset(size.width - radius, size.height - radius)
Custom Offset(x, y)

How to Position an object on Screen in Jetpack Compose Canvas

@Composable
fun CanvasDemoScreen() {
val imageBitmap = ImageBitmap.imageResource(R.drawable.image)
Canvas(modifier = Modifier.fillMaxSize()) {
drawImage(
image = imageBitmap,
topLeft = Offset(70f, 150f)
)
}
}

1. Basic Drawing Functions

These functions allow you to draw simple geometric shapes.
drawRect() - Draws a circle
package com.example.jetpackskill

import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color

@Composable
fun CanvasDemoScreen() {
Canvas(modifier = Modifier.fillMaxSize()) {
drawCircle(
color = Color.Red,
radius = 100f,
center = Offset(size.width / 2, size.height / 2)
)
}
}
OUTPUT:
Draws a circle Output
  •  size: Represents the dimensions of the canvas.
  •  Offset(x, y): Defines a position on the canvas.
  •  drawCircle(), drawRect(), drawLine(), etc.: Functions to draw basic shapes.

2. Drawing Advanced Shapes

How to use Path to create complex shapes.
package com.example.jetpackskill

import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path

@Composable
fun CanvasDemoScreen() {
Canvas(modifier = Modifier.fillMaxSize()) {
val path = Path().apply {
moveTo(100f, 100f)
lineTo(300f, 100f)
lineTo(200f, 300f)
close()
}
drawPath(path, color = Color.Blue)
}
}
OUTPUT:
Drawing Advanced Shapes using Path output
  •  Path.moveTo(x, y): Moves the starting point of the path.
  •  lineTo(x, y): Draws a line from the current point to (x, y).
  •  close(): Closes the shape, connecting the last point to the first.

3. Applying Transformations (Translate, Rotate, Scale)

We use  rotate(), translate(), and scale() for transformations. 
package com.example.jetpackskill

import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.rotate

@Composable
fun CanvasDemoScreen() {
Canvas(modifier = Modifier.fillMaxSize()) {
rotate(45f, pivot = Offset(size.width / 4, size.height / 2)) {
drawRect(Color.Green, size = Size(200f, 200f))
}
}
}
OUTPUT:
Applying Transformations Output
  • rotate(angle, pivot): Rotates the content.
  • translate(x, y): Moves the drawing position.
  • scale(factorX, factorY): Scales the drawing.

4. Animating Canvas Drawings

For animations, use rememberInfiniteTransition() with animated values.
package com.example.jetpackskill

import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color

@Composable
fun CanvasDemoScreen() {
val infiniteTransition = rememberInfiniteTransition()
val animatedRadius by infiniteTransition.animateFloat(
initialValue = 50f,
targetValue = 150f,
animationSpec = infiniteRepeatable(
animation = tween(durationMillis = 1000,
easing = LinearEasing),
repeatMode = RepeatMode.Reverse
)
)

Canvas(modifier = Modifier.fillMaxSize()) {
drawCircle(Color.Magenta, radius = animatedRadius, center = center)
}
}
  • rememberInfiniteTransition(): Keeps the animation running.
  • animateFloat(): Animates a float property.
  • infiniteRepeatable(): Loops the animation infinitely.

5. Handling Touch Input in Canvas

We can use Modifier.pointerInput() to detect user gestures.
package com.example.jetpackskill

import androidx.compose.foundation.Canvas
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput

@Composable
fun CanvasDemoScreen() {
var position by remember { mutableStateOf(Offset(200f, 200f)) }

Canvas(modifier = Modifier
.fillMaxSize()
.pointerInput(Unit) {
detectTapGestures { tapOffset -> position = tapOffset }
}
) {
drawCircle(Color.Cyan, radius = 50f, center = position)
}
}
  • detectTapGestures { tapOffset }: Detects tap events.
  • utableStateOf(Offset()): Stores the tap position.

Output:

Lets draw text in Canvas using gradient brush

To draw text what we are going to use?
  1. Canvas Composable: The drawText function is part of DrawScope, which is available inside the Canvas composable.
  2. textMeasurer.measure(...): This measures the text before drawing it.
  3. drawText(...): This is called inside the Canvas drawing scope.
  4. Bigger and bolder text: (40.sp, FontWeight.Bold).
  5. White text with a black shadow: for better visibility.
  6. Gradient color effect using Brush.linearGradient.
  7. Blurred shadow: for a cool glowing effect.
package com.example.jetpackskill

import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shadow
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.drawText
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.rememberTextMeasurer
import androidx.compose.ui.unit.sp

@Composable
fun CanvasScreenDemo(modifier: Modifier = Modifier) {
val textMeasurer = rememberTextMeasurer()

Canvas(modifier = modifier.fillMaxSize()) {
val textLayoutResult = textMeasurer.measure(
text = "Hello, Canvas!",
style = TextStyle(
fontSize = 40.sp,
fontWeight = FontWeight.Bold,
color = Color.White,
shadow = Shadow(
color = Color.Black, // Shadow color
offset = Offset(4f, 4f), // Shadow offset
blurRadius = 8f // Shadow blur
)
)
)

// Create a gradient effect using a linear gradient shader
val gradientBrush = Brush.linearGradient(
colors = listOf(Color.Magenta, Color.Cyan, Color.Blue),
start = Offset.Zero,
end = Offset(300f, 0f)
)

drawText(
textLayoutResult,
topLeft = Offset(100f, 200f),
brush = gradientBrush // Apply the gradient color
)
}
}

OUTPUT:

Draw a beautiful text in Canvas using brush Output

For more information about canvas visit the official Google website

Previous Post Next Post

Contact Form