Canvas in Android: cos’è, classe Canvas e metodi draw

Autore: IT Sectr Pubblicato: 2026-07-21 Tempo di lettura: 7 min

Canvas in Android — è una classe del pacchetto android.graphics che fornisce un’API per il rendering 2D su View. Canvas funziona come una tela su cui lo sviluppatore disegna forme geometriche, testo, immagini e percorsi utilizzando vari metodi draw*. Secondo la Documentazione per Sviluppatori Android (2025), Canvas è lo strumento principale per il rendering personalizzato in Android e viene utilizzato insieme alla classe Paint per definire stili e colori. Ogni chiamata onDraw() riceve un’istanza Canvas pronta, associata al buffer bitmap della view.

Punti Chiave

  • Canvas — una classe per il rendering 2D in Android, fornisce i metodi drawRect, drawCircle, drawText, drawBitmap e altri
  • Paint — una classe che definisce lo stile di rendering: colore, spessore, riempimento, effetti (ombra, gradiente)
  • onDraw(Canvas) — il metodo di View in cui avviene tutto il rendering tramite il Canvas ricevuto
  • Canvas.save() e restore() — gestione dello stack di trasformazioni per trasformazioni annidate del sistema di coordinate
  • Path — una classe per costruire contorni e curve arbitrari, passata a drawPath(Path, Paint)

Cos’è Canvas in Android

Canvas — è la classe centrale della grafica 2D in Android che fornisce metodi per disegnare su un piano. Ogni Canvas è collegato a un Bitmap — un’area di memoria in cui vengono registrati i risultati delle operazioni di disegno. Quando una View viene ridisegnata, il sistema passa a onDraw() un Canvas già associato al buffer di quella View.

Canvas funziona in un sistema di coordinate in cui (0,0) è l’angolo in alto a sinistra, l’asse X va verso destra, l’asse Y verso il basso. Tutte le operazioni di disegno utilizzano lo stato corrente di Canvas, inclusa la matrice di trasformazione, l’area di ritaglio e lo stile Paint. Secondo la Documentazione Android (2025), l’API Canvas include oltre 30 metodi draw* per diversi tipi di primitive grafiche.

Canvas e Accelerazione Hardware

Da Android 3.0 (API 11) Canvas supporta l’accelerazione hardware tramite DisplayList. In modalità accelerata, le operazioni Canvas vengono registrate in una DisplayList e poi eseguite sulla GPU. Questo offre un significativo aumento delle prestazioni ma impone limitazioni: alcune operazioni Canvas (clipPath con clip non Path) non sono supportate in modalità accelerata.

Metodi di base di Canvas per il rendering

Canvas fornisce un insieme di metodi per disegnare primitive di base. Ogni metodo accetta parametri geometrici e un oggetto Paint che definisce lo stile visivo.

MetodoScopoEsempio
drawRect()Disegna un rettangolocanvas.drawRect(10f, 10f, 100f, 100f, paint)
drawCircle()Disegna un cerchiocanvas.drawCircle(50f, 50f, 30f, paint)
drawLine()Disegna una lineacanvas.drawLine(0f, 0f, 100f, 100f, paint)
drawText()Disegna testocanvas.drawText(“Hello”, 10f, 20f, paint)
drawBitmap()Disegna un’immaginecanvas.drawBitmap(bitmap, 0f, 0f, paint)
drawPath()Disegna un percorso arbitrariocanvas.drawPath(path, paint)
drawOval()Disegna un ovalecanvas.drawOval(rectF, paint)
drawArc()Disegna un arco o settorecanvas.drawArc(rectF, 0f, 90f, true, paint)

Ogni metodo può essere chiamato in qualsiasi ordine — Canvas disegna nell’ordine delle chiamate, sovrapponendo nuovi elementi sopra quelli precedenti. Per composizioni complesse, viene utilizzata la tecnica di rendering multistrato con salvataggio e ripristino dello stato di Canvas.

Classe Paint: configurazione di stili ed effetti

Paint — è la classe che definisce come Canvas disegnerà. Senza Paint, i metodi Canvas sono inutili — imposta colore, spessore della linea, stile di riempimento, dimensione del testo, effetti (ombra, gradiente, sfocatura) e modalità di fusione.

Paint ha proprietà chiave: color (colore), style (FILL, STROKE o FILL_AND_STROKE), strokeWidth (spessore del tratto), textSize (dimensione del testo), isAntiAlias (antialiasing), shader (gradiente o immagine). Creare un oggetto Paint è un’operazione costosa, quindi dovrebbe essere creato una volta e riutilizzato.

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 questo esempio, vengono utilizzati due oggetti Paint: uno per riempire il cerchio di viola, il secondo per il tratto bianco. Separare riempimento e tratto è una pratica standard che consente un controllo flessibile dell’aspetto senza ricreare oggetti.

Shader e gradienti

Per i riempimenti sfumati, Paint accetta uno Shader — le sottoclassi LinearGradient, RadialGradient, SweepGradient. Shader viene collegato a Paint tramite il metodo setShader() e definisce come il colore cambia nell’area di disegno.

Trasformazioni di Canvas: translate, rotate, scale

Canvas supporta trasformazioni matriciali del sistema di coordinate: translate() (traslazione), rotate() (rotazione), scale() (scala) e skew() (inclinazione). Le trasformazioni si accumulano: ogni chiamata successiva viene applicata sopra le precedenti.

La gestione dello stack di trasformazioni avviene tramite save() e restore(). save() salva lo stato corrente di Canvas (matrice, ritaglio) nello stack, restore() ripristina l’ultimo stato salvato. Tra save() e restore() possono essere applicate trasformazioni annidate.

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
}

Utilizzare sempre save() prima di iniziare le trasformazioni e restore() dopo averle completate. Le coppie save/restore sbilanciate portano all’accumulo della matrice e al rendering errato degli elementi successivi.

Canvas con Bitmap e Path per grafica complessa

Per la grafica complessa, Canvas viene combinato con Bitmap e Path. Bitmap viene utilizzato per caricare immagini e memorizzare nella cache i frame renderizzati. Path viene utilizzato per costruire curve di Bezier arbitrari, poligoni e contorni complessi.

Buffer Bitmap offscreen

La tecnica di rendering offscreen: viene creato un Bitmap, una scena complessa viene disegnata su di esso tramite un Canvas separato, e poi il Bitmap finito viene visualizzato in onDraw() tramite drawBitmap(). Ciò consente di aggiornare grafica complessa senza ridisegnare completamente ogni 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 viene utilizzato per costruire contorni complessi: curve di Bezier (quadTo, cubicTo), archi (arcTo), linee (lineTo). Path può essere chiuso (close()) per forme riempite o aperto per linee. Il metodo principale drawPath() combina Path e Paint per il rendering finale.

Ottimizzazione del rendering di Canvas

Le prestazioni del rendering di Canvas influenzano direttamente gli FPS dell’applicazione. I problemi principali: allocazioni eccessive in onDraw(), chiamate frequenti a invalidate() e uso subottimale dell’Accelerazione Hardware.

Creare oggetti al di fuori di onDraw()

Paint, Path, Rect, RectF e altri oggetti dovrebbero essere creati una volta nell’inizializzatore o nel metodo setup(). Ogni allocazione in onDraw() crea pressione sul garbage collector, causando micro-ritardi. L’eccezione sono gli oggetti static o companion object per oggetti immutabili.

Utilizzare clipRect() per limitare l’area

Se la maggior parte della View è nascosta al di fuori dell’area visibile (ad esempio, in ScrollView), utilizzare canvas.clipRect() per limitare il rendering. L’Accelerazione Hardware in questo caso ottimizza ulteriormente il ritaglio dei pixel invisibili.

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()
}

Utilizzare View.setLayerType() con LAYER_TYPE_HARDWARE per Views con grafica Canvas complessa che vengono aggiornate raramente. Per animazioni aggiornate frequentemente, utilizzare invece LAYER_TYPE_NONE per evitare costosi aggiornamenti del layer hardware. Eseguire il profiling con GPU Profile Rendering e Android Studio Profiler.

Domande Frequenti

Si può creare un Canvas senza una View?

Sì, è possibile creare Canvas(Bitmap) — un costruttore che accetta un Bitmap. Ciò viene utilizzato per il rendering offscreen: si disegna su un Bitmap e poi lo si visualizza tramite drawBitmap(). Canvas può anche essere creato da Surface (per SurfaceView) o tramite Picture.

Qual è la differenza tra Canvas e SurfaceView?

Canvas — è un’API per disegnare su View nel thread UI. SurfaceView — è una Surface separata che può essere aggiornata da un thread in background tramite il proprio Canvas (lockCanvas() / unlockCanvasAndPost()). SurfaceView è preferibile per giochi e video.

Perché Canvas non disegna dopo una trasformazione?

Il motivo più comune sono le coppie sbilanciate di save() e restore(). Se dopo una trasformazione (translate, rotate) restore() non viene chiamato, Canvas rimane in un sistema di coordinate modificato e gli elementi successivi vengono disegnati con uno scostamento. Verificare le proprie coppie save()/restore().

Come disegnare testo centrato su Canvas?

Utilizzare Paint.setTextAlign(Paint.Align.CENTER) per il centraggio orizzontale e Paint.getTextBounds() o Paint.descent() / ascent() per quello verticale. Centraggio: canvas.drawText(testo, centerX, centerY - (ascent + descent) / 2, paint).

Canvas supporta l’animazione?

Canvas di per sé non anima — disegna solo lo stato corrente. L’animazione si ottiene tramite chiamate successive a invalidate() (o postInvalidateOnAnimation()), disegnando ogni volta un nuovo frame in onDraw(). Per animazioni fluide, utilizzare ValueAnimator o Choreographer per sincronizzarsi con Vsync.

Riepilogo

  • Canvas — la classe centrale di rendering 2D in Android, fornisce metodi draw* per disegnare primitive, testo e immagini
  • Paint — definisce lo stile visivo (colore, spessore, riempimento, shader); creato una volta e riutilizzato
  • save() / restore() — gestione dello stack di trasformazioni; ogni trasformazione deve essere in una coppia save/restore
  • Path — costruzione di contorni arbitrari e curve di Bezier per grafica vettoriale complessa
  • Offscreen Bitmap — tecnica di caching di scene complesse tramite Canvas(Bitmap) per ridurre il carico su onDraw()
  • Accelerazione Hardware — accelerazione GPU di Canvas da Android 3.0, impone limitazioni su alcune operazioni (clipPath)
  • Profiling — GPU Profile Rendering e Android Studio Profiler sono obbligatori per trovare colli di bottiglia in onDraw()

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche