Canvas in Android: what it is, Canvas class and draw methods

Author: IT Sectr Published: 2026-07-21 Reading time: 7 min

Canvas in Android — is a class from the android.graphics package that provides an API for 2D rendering on View. Canvas works as a canvas on which the developer draws geometric shapes, text, images and paths using various draw* methods. According to the Android Developers Documentation (2025), Canvas is the primary tool for custom rendering in Android and is used together with the Paint class to define styles and colors. Each onDraw() call receives a ready Canvas instance associated with the view’s bitmap buffer.

Key Takeaways

  • Canvas — a class for 2D rendering in Android, provides drawRect, drawCircle, drawText, drawBitmap and other methods
  • Paint — a class that defines the rendering style: color, thickness, fill, effects (shadow, gradient)
  • onDraw(Canvas) — the View method where all rendering occurs through the received Canvas
  • Canvas.save() and restore() — managing the transformation stack for nested coordinate system transformations
  • Path — a class for building arbitrary contours and curves, passed to drawPath(Path, Paint)

What is Canvas in Android

Canvas — is the central 2D graphics class in Android that provides methods for drawing on a plane. Each Canvas is attached to a Bitmap — a memory area where the results of drawing operations are recorded. When a View is redrawn, the system passes to onDraw() a Canvas already associated with that View’s buffer.

Canvas works in a coordinate system where (0,0) is the top-left corner, the X axis goes right, the Y axis goes down. All drawing operations use the current state of Canvas, including the transformation matrix, clipping area and Paint style. According to Android Documentation (2025), the Canvas API includes over 30 draw* methods for different types of graphic primitives.

Canvas and Hardware Acceleration

Since Android 3.0 (API 11) Canvas supports hardware acceleration through DisplayList. In accelerated mode, Canvas operations are recorded into a DisplayList and then executed on the GPU. This provides a significant performance boost but imposes limitations: some Canvas operations (clipPath with non-Path clip) are not supported in accelerated mode.

Basic Canvas rendering methods

Canvas provides a set of methods for drawing basic primitives. Each method accepts geometric parameters and a Paint object that defines the visual style.

MethodPurposeExample
drawRect()Draws a rectanglecanvas.drawRect(10f, 10f, 100f, 100f, paint)
drawCircle()Draws a circlecanvas.drawCircle(50f, 50f, 30f, paint)
drawLine()Draws a linecanvas.drawLine(0f, 0f, 100f, 100f, paint)
drawText()Draws textcanvas.drawText(“Hello”, 10f, 20f, paint)
drawBitmap()Draws an imagecanvas.drawBitmap(bitmap, 0f, 0f, paint)
drawPath()Draws an arbitrary pathcanvas.drawPath(path, paint)
drawOval()Draws an ovalcanvas.drawOval(rectF, paint)
drawArc()Draws an arc or sectorcanvas.drawArc(rectF, 0f, 90f, true, paint)

Each method can be called in any order — Canvas draws in the order of calls, layering new elements on top of previous ones. For complex compositions, the multi-layer rendering technique with saving and restoring Canvas state is used.

Paint class: configuring styles and effects

Paint — is the class that defines how Canvas will draw. Without Paint, Canvas methods are useless — it sets color, line thickness, fill style, text size, effects (shadow, gradient, blur) and blending mode.

Paint has key properties: color, style (FILL, STROKE or FILL_AND_STROKE), strokeWidth, textSize, isAntiAlias, shader (gradient or image). Creating a Paint object is an expensive operation, so it should be created once and reused.

kotlin
private val fillPaint = Paint().apply {
    color = Color.parseColor("#FF6200EE")
    style = Paint.Style.FILL
    isAntiAlias = true
}

private val strokePaint = Paint().apply {
    color = Color.WHITE
    style = Paint.Style.STROKE
    strokeWidth = 4f
    isAntiAlias = true
}

override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    canvas.drawCircle(100f, 100f, 80f, fillPaint)
    canvas.drawCircle(100f, 100f, 80f, strokePaint)
}

In this example, two Paint objects are used: one for filling the circle with purple color, the second for white stroke. Separating fill and stroke is a standard practice that allows flexible control of appearance without recreating objects.

Shader and gradients

For gradient fills, Paint accepts a Shader — subclasses LinearGradient, RadialGradient, SweepGradient. Shader is attached to Paint through the setShader() method and defines how color changes across the drawing area.

Canvas transformations: translate, rotate, scale

Canvas supports matrix transformations of the coordinate system: translate(), rotate(), scale() and skew(). Transformations accumulate: each subsequent call is applied on top of previous ones.

Managing the transformation stack is done through save() and restore(). save() saves the current Canvas state (matrix, clip) to the stack, restore() restores the last saved state. Between save() and restore(), nested transformations can be applied.

kotlin
override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)

    canvas.save() // Save initial state
    canvas.translate(100f, 100f) // Translate origin

    // First square
    canvas.drawRect(0f, 0f, 50f, 50f, fillPaint)

    canvas.save() // Save after translate
    canvas.rotate(45f, 25f, 25f) // Rotate around square center

    // Rotated square
    canvas.drawRect(0f, 0f, 50f, 50f, strokePaint)
    canvas.restore() // Restore after rotate

    canvas.restore() // Restore initial state
}

Always use save() before starting transformations and restore() after completing them. Unbalanced save/restore leads to matrix accumulation and incorrect rendering of subsequent elements.

Canvas with Bitmap and Path for complex graphics

For complex graphics, Canvas is combined with Bitmap and Path. Bitmap is used for loading images and caching rendered frames. Path is used for building arbitrary Bezier curves, polygons and complex contours.

Offscreen Bitmap buffer

The offscreen rendering technique: a Bitmap is created, a complex scene is drawn onto it through a separate Canvas, and then the finished Bitmap is output in onDraw() via drawBitmap(). This allows updating complex graphics without full redraw on each frame.

kotlin
private var offscreenBitmap: Bitmap? = null
private var offscreenCanvas: Canvas? = null

fun buildOffscreenScene(width: Int, height: Int) {
    offscreenBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
    offscreenCanvas = Canvas(offscreenBitmap)

    // Render scene once
    offscreenCanvas!!.drawColor(Color.WHITE)
    drawGrid(offscreenCanvas!!)
    drawComplexShape(offscreenCanvas!!)
}

override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    offscreenBitmap?.let { canvas.drawBitmap(it, 0f, 0f, null) }
}

Path is used for building complex contours: Bezier curves (quadTo, cubicTo), arcs (arcTo), lines (lineTo). Path can be closed (close()) for filled shapes or open for lines. The main drawPath() method combines Path and Paint for final rendering.

Canvas rendering optimization

Canvas rendering performance directly affects application FPS. The main issues: excessive allocations in onDraw(), frequent invalidate() calls and suboptimal use of Hardware Acceleration.

Create objects outside onDraw()

Paint, Path, Rect, RectF and other objects should be created once in the initializer or setup() method. Each allocation in onDraw() creates garbage collector pressure, leading to micro-lags. The exception is static or companion object for immutable objects.

Use clipRect() to limit the area

If most of the View is hidden outside the visible area (for example, in ScrollView), use canvas.clipRect() to limit rendering. Hardware Acceleration in this case additionally optimizes clipping of invisible pixels.

kotlin
override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)

    // Clip to visible area
    canvas.save()
    canvas.clipRect(scrollX, scrollY, scrollX + width, scrollY + height)

    // Render large scene
    renderScene(canvas)
    canvas.restore()
}

Use View.setLayerType() with LAYER_TYPE_HARDWARE for Views with complex Canvas graphics that update infrequently. For frequently updated animation, conversely, use LAYER_TYPE_NONE to avoid expensive hardware layer updates. Profile using GPU Profile Rendering and Android Studio Profiler.

Frequently Asked Questions

Can I create a Canvas without a View?

Yes, you can create Canvas(Bitmap) — a constructor that accepts a Bitmap. This is used for offscreen rendering: you draw on a Bitmap, and then output it via drawBitmap(). Canvas can also be created from Surface (for SurfaceView) or through Picture.

How is Canvas different from SurfaceView?

Canvas — is an API for drawing on View in the UI thread. SurfaceView — is a separate Surface that can be updated from a background thread through its own Canvas (lockCanvas() / unlockCanvasAndPost()). SurfaceView is preferred for games and video.

Why doesn’t Canvas draw after transformation?

The most common reason is unbalanced save() and restore(). If after a transformation (translate, rotate) restore() is not called, the Canvas remains in a modified coordinate system, and subsequent elements are drawn with an offset. Check your save()/restore() pairs.

How to draw text centered on Canvas?

Use Paint.setTextAlign(Paint.Align.CENTER) for horizontal centering and Paint.getTextBounds() or Paint.descent() / ascent() for vertical. Centering: canvas.drawText(text, centerX, centerY - (ascent + descent) / 2, paint).

Does Canvas support animation?

Canvas itself does not animate — it only draws the current state. Animation is achieved through sequential calls to invalidate() (or postInvalidateOnAnimation()), each time drawing a new frame in onDraw(). For smooth animations use ValueAnimator or Choreographer to sync with Vsync.

Summary

  • Canvas — the central 2D rendering class in Android, provides draw* methods for drawing primitives, text and images
  • Paint — defines the visual style (color, thickness, fill, shaders); created once and reused
  • save() / restore() — managing the transformation stack; each transformation must be in a save/restore pair
  • Path — building arbitrary contours and Bezier curves for complex vector graphics
  • Offscreen Bitmap — a technique for caching complex scenes via Canvas(Bitmap) to reduce onDraw() load
  • Hardware Acceleration — GPU acceleration of Canvas since Android 3.0, imposes limitations on some operations (clipPath)
  • Profiling — GPU Profile Rendering and Android Studio Profiler are mandatory for finding bottlenecks in onDraw()

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also