onDraw() — cos’è, meccanismo di chiamata e override del metodo

Autore: IT Sectr Pubblicato: 2026-07-22 Tempo di lettura: 10 min

onDraw() è un metodo chiave della classe View nell’Android SDK responsabile del disegno del contenuto di una vista. Il sistema chiama onDraw a ogni aggiornamento dell’aspetto della View — durante il rendering iniziale, dopo invalidate() o quando le dimensioni cambiano. Secondo la documentazione di Android Developers (2026), l’override di onDraw utilizzando l’API Canvas è il modo principale per creare grafica personalizzata nelle applicazioni Android.

Punti chiave

  • onDraw(Canvas) — un metodo di View chiamato dal sistema per disegnare il contenuto sul Canvas
  • invalidate() — una richiesta di ridisegno della View, che porta alla chiamata di onDraw nel ciclo di frame successivo
  • Canvas API fornisce i metodi drawCircle, drawBitmap, drawText, drawPath e altri per disegnare
  • Il sistema Android esegue il disegno nel thread UI, quindi onDraw deve essere leggero e veloce
  • Hardware acceleration accelera automaticamente il disegno attraverso la GPU, a partire da Android 3.0 (API 11)

Cos’è onDraw()?

onDraw(Canvas canvas) è un metodo protected della classe android.view.View, che il sistema Android chiama quando una View deve essere disegnata. Lo sviluppatore sovrascrive questo metodo per implementare il disegno personalizzato: forme, testo, immagini, gradienti, animazioni. Il parametro Canvas è una superficie grafica su cui vengono eseguite tutte le operazioni di disegno.

La firma del metodo è semplice: override fun onDraw(canvas: Canvas). All’interno di questo metodo, non si devono creare nuovi oggetti (per evitare il carico del GC), eseguire operazioni lunghe o lavorare con la rete. View include anche il metodo onDraw nel suo ciclo di vita tra onLayout (calcolo delle posizioni) e dispatchDraw (disegno degli elementi figli).

Quando si eredita da View, l’override di onDraw è obbligatorio per visualizzare qualsiasi contenuto — altrimenti la View sarà vuota. Quando si eredita da sottoclassi esistenti (TextView, ImageView, Button), l’override di onDraw è opzionale e viene utilizzato per aggiungere grafica aggiuntiva sopra il contenuto standard.

Ciclo di disegno della View

Android esegue il disegno della View in una sequenza rigorosamente definita chiamata dal thread principale (UI thread). Il ciclo completo consiste in tre fasi: measure (misurazione delle dimensioni), layout (calcolo delle posizioni) e draw (rendering). onDraw fa parte della fase draw e viene chiamato dopo che le dimensioni e la posizione della View sono state determinate.

Fase draw: dispatchDraw e onDraw

draw(Canvas canvas) è un metodo pubblico di View che chiama onDraw e dispatchDraw. Il metodo draw non è progettato per essere sovrascritto — invece, viene sovrascritto onDraw. Dopo l’esecuzione di onDraw per la View corrente, viene chiamato dispatchDraw, che invoca ricorsivamente draw per tutte le View figlie (se la View corrente è un contenitore ViewGroup).

Quando il sistema chiama onDraw

onDraw viene chiamato nelle seguenti condizioni: 1) la View diventa visibile per la prima volta (dopo setVisibility(VISIBLE)); 2) l’app chiama invalidate() su questa View o sul suo genitore; 3) la dimensione della View cambia (nuovo layout); 4) un’animazione associata alla View cambia (tramite ValueAnimator o ObjectAnimator); 5) lo stato della View cambia (pressed, focused, enabled).

Accelerazione hardware

Da Android 3.0 (API 11), la maggior parte delle operazioni Canvas sono accelerate via hardware attraverso la GPU. Lo sviluppatore può verificare se l’accelerazione è abilitata tramite canvas.isHardwareAccelerated(). Con l’accelerazione hardware, alcune operazioni Canvas non sono supportate (ad esempio, clipPath con una regione non rettangolare) e possono essere ignorate o causare errori.

Canvas API per grafica personalizzata

Canvas fornisce un ricco insieme di metodi di disegno. Tutti i metodi funzionano nel sistema di coordinate corrente, che può essere modificato attraverso trasformazioni (translate, rotate, scale, skew). Ogni metodo accetta un oggetto Paint che definisce colore, stile, spessore della linea, effetti e anti-aliasing.

Metodo CanvasScopoParametri chiave di Paint
drawCircleDisegnare un cerchiocenterX, centerY, radius, paint
drawRectDisegnare un rettangololeft, top, right, bottom, paint
drawLineDisegnare una lineastartX, startY, endX, endY, paint
drawPathDisegnare un percorso arbitrariopath, paint
drawBitmapDisegnare un’immagine bitmapbitmap, srcRect, dstRect, paint
drawTextDisegnare testotext, x, y, paint
drawArcDisegnare un arco o settoreovalRect, startAngle, sweepAngle, useCenter, paint
drawOvalDisegnare un ovaleovalRect, paint

L’oggetto Paint

Paint definisce lo stile di disegno: colore (setColor), spessore della linea (setStrokeWidth), stile di riempimento (setStyle — FILL, STROKE, FILL_AND_STROKE), anti-aliasing (setAntiAlias), effetti (setShadowLayer, setMaskFilter) e gradienti (setShader). Si consiglia di creare e configurare Paint una volta nel costruttore della View, non all’interno di onDraw, per evitare la creazione di oggetti nel ciclo di disegno.

Coordinate e trasformazioni

Canvas utilizza un sistema di coordinate in cui l’asse X punta a destra e l’asse Y verso il basso. L’origine (0, 0) è l’angolo superiore sinistro della View. Prima di chiamare i metodi di disegno, lo sviluppatore può modificare il sistema di coordinate tramite canvas.translate(dx, dy), canvas.rotate(degrees, px, py), canvas.scale(sx, sy, px, py). Tutte le operazioni di disegno successive verranno eseguite nel sistema trasformato.

Prestazioni di onDraw

onDraw viene eseguito nel thread principale UI e la sua durata influisce direttamente sul frame rate (fps). Per mantenere 60 fps, il metodo onDraw deve essere completato entro 16 millisecondi. Qualsiasi rallentamento porta a cadute di frame (jank), che visivamente appaiono come balbuzie dell’animazione o ritardo nello scorrimento.

Regole di prestazione per onDraw

Regole principali per l’ottimizzazione di onDraw includono: 1) non creare oggetti all’interno di onDraw — tutti gli oggetti Paint, Path, Rect devono essere campi della classe; 2) non allocare memoria (new) — questo attiva la garbage collection (GC) e cadute di frame; 3) memorizzare nella cache le operazioni complesse in un Bitmap tramite Bitmap.createBitmap e disegnare il Bitmap preparato; 4) non eseguire operazioni di I/O o caricamento di risorse.

Utilizzo di clipRect per l’ottimizzazione

clipRect limita l’area di disegno a un rettangolo specificato. Viene utilizzato per evitare che Canvas perda tempo a disegnare pixel fuori dall’area visibile. Particolarmente efficace durante lo scorrimento di grandi elenchi o lo zoom: imposta clipRect sull’area visibile (dirty rect) e Canvas disegnerà solo ciò che è visibile.

Layer — salvare e ripristinare

canvas.save() salva lo stato corrente del Canvas (trasformazione e clip) su uno stack. canvas.restore() ripristina l’ultimo stato salvato. Necessario per trasformazioni temporanee: salva lo stato, applica translate/rotate, disegna, quindi ripristina. save e restore sono leggeri e non influiscono sulle prestazioni se usati ragionevolmente (meno di 10–15 livelli di annidamento).

invalidate e postInvalidate

invalidate() è un metodo di View che informa il sistema che il contenuto della View è obsoleto e deve essere ridisegnato. Chiamare invalidate avvia un nuovo ciclo di draw in cui verrà chiamato onDraw. invalidate deve essere chiamato solo dal thread UI (thread principale). Per chiamarlo da un thread in background, si usa postInvalidate.

postInvalidate() è una versione thread-safe di invalidate che invia una richiesta di ridisegno alla coda del thread principale tramite Handler. Viene utilizzata in attività di background quando la View deve essere aggiornata dopo il completamento del caricamento dei dati o dei calcoli. Può essere combinata con runOnUiThread per la sincronizzazione con l’UI.

Per il ridisegno parziale, utilizzare invalidate(Rect dirty) o invalidate(int l, int t, int r, int b). Questo indica al sistema che solo l’area specificata è cambiata, non l’intera View. Android ottimizza il disegno ridisegnando solo il dirty rect, migliorando significativamente le prestazioni per le animazioni con aggiornamenti parziali.

Esempi di codice in Kotlin

Vediamo esempi pratici di override di onDraw per creare View personalizzate in Android usando Kotlin.

View personalizzata — Progresso circolare

Questo esempio crea un indicatore di progresso circolare con riempimento animato. onDraw disegna due cerchi: un cerchio di sfondo grigio e un cerchio di riempimento colorato il cui arco è determinato dal progresso corrente. La chiamata a invalidate in setProgress garantisce il ridisegno quando il valore cambia.

kotlin
class CircularProgressView
    @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null
) : View(context, attrs) {

    private val bgPaint = Paint().apply {
        style = Paint.Style.STROKE
        strokeWidth = 12f
        color = Color.parseColor("#E0E0E0")
        isAntiAlias = true
    }

    private val progressPaint = Paint().apply {
        style = Paint.Style.STROKE
        strokeWidth = 12f
        color = Color.BLUE
        isAntiAlias = true
        strokeCap = Paint.Cap.ROUND
    }

    var progress: Float = 0f
        set(value) {
            field = value.coerceIn(0f, 1f)
            invalidate()
        }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val size = minOf(width, height) - 24f
        val oval = RectF(12f, 12f,
                          12f + size, 12f + size)

        canvas.drawArc(oval, 270f, 360f, false, bgPaint)
        canvas.drawArc(oval, 270f,
                        progress * 360f,
                        false, progressPaint)
    }
}

View personalizzata — Sfondo sfumato con testo

Questo esempio disegna un rettangolo con sfumatura e testo sopra di esso. La sfumatura viene creata tramite LinearGradient (Shader) e il testo tramite drawText. Entrambi gli oggetti Paint vengono creati una volta nel costruttore, mentre onDraw aggiorna solo la dimensione del rettangolo in base alla larghezza corrente della View.

kotlin
class GradientTextView(context: Context)
    : View(context) {

    private val shaderPaint = Paint().apply {
        isAntiAlias = true
    }

    private val textPaint = Paint().apply {
        color = Color.WHITE
        textSize = 48f
        isAntiAlias = true
        textAlign = Paint.Align.CENTER
    }

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

        val gradient = LinearGradient(
            0f, 0f, width.toFloat(), 0f,
            Color.parseColor("#FF6B35"),
            Color.parseColor("#FF0040"),
            Shader.TileMode.CLAMP
        )
        shaderPaint.shader = gradient
        canvas.drawRect(0f, 0f,
                        width.toFloat(),
                        height.toFloat(), shaderPaint)

        val xCenter = width / 2f
        val yCenter = height / 2f
        val yOffset = (textPaint.descent() +
                        textPaint.ascent()) / 2f

        canvas.drawText("Hello from Canvas",
                      xCenter, yCenter - yOffset,
                      textPaint)
    }
}

Orologio animato che utilizza invalidate

Questo esempio crea un orologio animato che aggiorna il disegno ogni 1000 millisecondi. postDelayed all’interno di onDraw chiama invalidate dopo un secondo, creando un ciclo di ridisegno infinito. Le lancette dell’orologio vengono disegnate tramite drawLine con diverse lunghezze e spessori.

kotlin
class AnalogClockView(context: Context)
    : View(context) {

    private val handPaint = Paint().apply {
        style = Paint.Style.STROKE
        isAntiAlias = true
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val cx = width / 2f
        val cy = height / 2f
        val radius = minOf(cx, cy) - 20f

        val now = Calendar.getInstance()
        val hours = now.get(Calendar.HOUR) % 12
        val minutes = now.get(Calendar.MINUTE)
        val seconds = now.get(Calendar.SECOND)

        val secondAngle = Math.toRadians(
            seconds * 6f - 90f)
        handPaint.strokeWidth = 2f
        handPaint.color = Color.RED
        canvas.drawLine(cx, cy,
            cx + cos(secondAngle) * radius * 0.8f,
            cy + sin(secondAngle) * radius * 0.8f,
            handPaint)

        postDelayed({ invalidate() }, 1000)
    }
}

Domande frequenti

Si può chiamare onDraw direttamente?

No, non si deve chiamare onDraw direttamente. Per richiedere un ridisegno, utilizzare invalidate() (dal thread UI) o postInvalidate() (da un thread in background). Il sistema deciderà quando chiamare onDraw e ottimizzerà il disegno unendo più chiamate invalidate in un unico passaggio.

Perché onDraw non viene chiamato dopo invalidate?

Ragioni: la View è nascosta (setVisibility(GONE) o INVISIBLE); la View non è stata aggiunta alla gerarchia della Window; la dimensione della View è 0 (larghezza o altezza = 0); viene chiamato setWillNotDraw(true) (true per impostazione predefinita per ViewGroup). Controllare ciascuno di questi punti durante il debug.

Con quale frequenza può essere chiamato onDraw?

A 60 fps, onDraw può essere chiamato fino a 60 volte al secondo. A 120 fps (su dispositivi con display a 120 Hz) — fino a 120 volte. Ogni chiamata deve essere completata entro circa 8–16 millisecondi. Durante le animazioni attive tramite ObjectAnimator o ValueAnimator, la frequenza è determinata dal numero di frame dell’animazione.

Qual è la differenza tra onDraw e dispatchDraw?

onDraw è responsabile del disegno del contenuto della View stessa. dispatchDraw è responsabile del disegno delle View figlie (in ViewGroup). dispatchDraw viene chiamato dopo onDraw e attraversa ricorsivamente tutti gli elementi figli. Per una View normale (non ViewGroup), dispatchDraw è vuoto.

Si può usare Canvas al di fuori di onDraw?

, è possibile creare un Canvas per un Bitmap tramite Canvas(bitmap) e disegnarci sopra in qualsiasi thread. Viene utilizzato per pre-rendering di grafica complessa in background. Tuttavia, il Canvas passato a onDraw appartiene al sistema e può essere utilizzato solo sul thread UI all’interno del metodo onDraw.

Riepilogo

  • onDraw(Canvas) — un metodo chiave di View per il disegno personalizzato con Canvas API in Android
  • Ciclo di disegno comprende le fasi measure, layout e draw — onDraw viene chiamato nella fase draw
  • Canvas API include i metodi drawCircle, drawRect, drawPath, drawBitmap, drawText e altri
  • invalidate() richiede il ridisegno dal thread UI, postInvalidate() da un thread in background
  • Ridisegno parziale tramite invalidate(Rect) ottimizza il rendering aggiornando solo l’area sporca
  • Prestazioni di onDraw sono critiche: creare oggetti all’interno del metodo causa GC e cadute di frame
  • Accelerazione hardware (da API 11) accelera automaticamente le operazioni Canvas attraverso la GPU

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