Canvas în Android: ce este, clasa Canvas și metodele draw

Autor: IT Sectr Publicat: 2026-07-21 Timp de citire: 7 min

Canvas în Android — este o clasă din pachetul android.graphics care oferă API pentru desenarea 2D pe View. Canvas funcționează ca o pânză pe care dezvoltatorul desenează figuri geometrice, text, imagini și căi cu ajutorul diferitelor metode draw*. Conform Android Developers Documentation (2025), Canvas este instrumentul principal pentru desenarea personalizată în Android și este folosit împreună cu clasa Paint pentru setarea stilurilor și culorilor. Fiecare apel onDraw() primește o instanță Canvas pregătită, asociată cu buffer-ul bitmap al view-ului.

Principalele puncte

  • Canvas — clasă pentru desenarea 2D în Android, oferă metodele drawRect, drawCircle, drawText, drawBitmap și altele
  • Paint — clasă care definește stilul de desenare: culoare, grosime, umplere, efecte (umbră, gradient)
  • onDraw(Canvas) — metoda View în care are loc întreaga desenare prin Canvas primit
  • Canvas.save() și restore() — gestionarea stivei de transformări pentru transformări imbricate ale sistemului de coordonate
  • Path — clasă pentru construirea de contururi și curbe arbitrare, transmisă în drawPath(Path, Paint)

Ce este Canvas în Android

Canvas — este clasa centrală de grafică 2D în Android care oferă metode pentru desenare pe suprafață. Fiecare Canvas este legat de un Bitmap — o zonă de memorie în care se scriu rezultatele operațiilor de desenare. Când View este redesenat, sistemul transmite în onDraw() un Canvas deja asociat cu buffer-ul acestui View.

Canvas funcționează într-un sistem de coordonate unde (0,0) este colțul din stânga sus, axa X merge la dreapta, axa Y în jos. Toate operațiile de desenare folosesc starea curentă a Canvas, inclusiv matricea de transformare, zona de decupare (clip) și stilul Paint. Conform Android Documentation (2025), API-ul Canvas include peste 30 de metode draw* pentru diferite tipuri de primitive grafice.

Canvas și Accelerarea Hardware

Începând cu Android 3.0 (API 11) Canvas suportă accelerarea hardware prin DisplayList. În modul accelerat, operațiile Canvas sunt scrise în DisplayList și apoi executate pe GPU. Aceasta oferă o creștere semnificativă a performanței, dar impune limitări: unele operații Canvas (clipPath cu clip non-Path) nu sunt suportate în modul accelerat.

Metodele principale Canvas pentru desenare

Canvas oferă un set de metode pentru desenarea primitivelor de bază. Fiecare metodă primește parametri geometrici și un obiect Paint care definește stilul vizual.

MetodăScopExemplu
drawRect()Desenarea unui dreptunghicanvas.drawRect(10f, 10f, 100f, 100f, paint)
drawCircle()Desenarea unui cerccanvas.drawCircle(50f, 50f, 30f, paint)
drawLine()Desenarea unei liniicanvas.drawLine(0f, 0f, 100f, 100f, paint)
drawText()Desenarea textuluicanvas.drawText("Hello", 10f, 20f, paint)
drawBitmap()Desenarea unei imaginicanvas.drawBitmap(bitmap, 0f, 0f, paint)
drawPath()Desenarea unei căi arbitrarecanvas.drawPath(path, paint)
drawOval()Desenarea unui ovalcanvas.drawOval(rectF, paint)
drawArc()Desenarea unui arc sau sectorcanvas.drawArc(rectF, 0f, 90f, true, paint)

Fiecare metodă poate fi apelată în orice ordine — Canvas desenează în ordinea apelurilor, suprapunând elemente noi peste cele anterioare. Pentru compoziții complexe se folosește tehnica desenării în mai multe straturi cu salvarea și restaurarea stării Canvas.

Clasa Paint: configurarea stilurilor și efectelor

Paint — este clasa care definește cum va desena Canvas. Fără Paint, metodele Canvas sunt inutile — acesta setează culoarea, grosimea liniei, stilul de umplere, dimensiunea textului, efectele (umbră, gradient, estompare) și modul de amestecare.

Paint are proprietăți cheie: color (culoare), style (FILL, STROKE sau FILL_AND_STROKE), strokeWidth (grosimea liniei), textSize (dimensiunea textului), isAntiAlias (netezire), shader (gradient sau imagine). Crearea unui obiect Paint este o operație costisitoare, de aceea trebuie creat o dată și reutilizat.

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

În acest exemplu se folosesc două Paint: unul pentru umplerea cercului cu violet, al doilea pentru conturul alb. Separarea în fill și stroke este o practică standard care permite gestionarea flexibilă a aspectului fără recrearea obiectelor.

Shader și gradiente

Pentru umpleri cu gradient, Paint primește un Shader — subclasele LinearGradient, RadialGradient, SweepGradient. Shader se atașează la Paint prin metoda setShader() și definește cum se schimbă culoarea pe zona de desenare.

Transformări Canvas: translate, rotate, scale

Canvas suportă transformări matriceale ale sistemului de coordonate: translate() (deplasare), rotate() (rotire), scale() (scalare) și skew() (înclinare). Transformările se acumulează: fiecare apel ulterior se aplică peste cele anterioare.

Gestionarea stivei de transformări se face prin save() și restore(). save() salvează starea curentă a Canvas (matrice, clip) în stivă, restore() restaurează ultima stare salvată. Între save() și restore() pot exista transformări imbricate.

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

    canvas.save() // Salvează starea inițială
    canvas.translate(100f, 100f) // Deplasează originea

    // Primul pătrat
    canvas.drawRect(0f, 0f, 50f, 50f, fillPaint)

    canvas.save() // Salvează după deplasare
    canvas.rotate(45f, 25f, 25f) // Rotește în jurul centrului pătratului

    // Pătrat rotit
    canvas.drawRect(0f, 0f, 50f, 50f, strokePaint)
    canvas.restore() // Restaurează după rotire

    canvas.restore() // Restaurează starea inițială
}

Folosiți întotdeauna save() înainte de a începe transformările și restore() după finalizarea lor. Save/restore dezechilibrate duc la acumularea matricei și desenarea incorectă a elementelor ulterioare.

Canvas cu Bitmap și Path pentru grafică complexă

Pentru grafică complexă, Canvas este combinat cu Bitmap și Path. Bitmap este folosit pentru încărcarea imaginilor și stocarea cadrelor randate. Path — pentru construirea de curbe Bezier arbitrare, poligoane și contururi complexe.

Buffer Bitmap offscreen

Tehnica de randare offscreen: se creează un Bitmap, pe el se desenează o scenă complexă printr-un Canvas separat, iar apoi Bitmap-ul rezultat este afișat în onDraw() prin drawBitmap(). Aceasta permite actualizarea graficii complexe fără redesenarea completă a fiecărui cadru.

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)

    // Randează scena o dată
    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 este folosit pentru construirea de contururi complexe: curbe Bezier (quadTo, cubicTo), arcuri (arcTo), linii (lineTo). Path poate fi închis (close()) pentru figuri umplute sau deschis pentru linii. Metodele principale drawPath() combină Path și Paint pentru desenarea finală.

Optimizarea desenării Canvas

Performanța desenării Canvas influențează direct FPS-ul aplicației. Problemele principale: alocări excesive în onDraw(), invalidate() frecvent și utilizarea neoptimală a Accelerării Hardware.

Creați obiecte în afara onDraw()

Paint, Path, Rect, RectF și alte obiecte trebuie create o singură dată în inițializator sau metoda setup(). Fiecare alocare în onDraw() creează sarcină pentru garbage collector, ceea ce duce la micro-întârzieri. Excepție — static sau companion object pentru obiecte imutabile.

Folosiți clipRect() pentru limitarea zonei

Dacă o parte mare a View este ascunsă în afara zonei vizibile (de exemplu, în ScrollView), folosiți canvas.clipRect() pentru a limita desenarea. Accelerarea Hardware în acest caz optimizează suplimentar decuparea pixelilor invizibili.

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

    // Decupează la zona vizibilă
    canvas.save()
    canvas.clipRect(scrollX, scrollY, scrollX + width, scrollY + height)

    // Randează scena mare
    renderScene(canvas)
    canvas.restore()
}

Folosiți View.setLayerType() cu LAYER_TYPE_HARDWARE pentru View cu grafică Canvas complexă care se actualizează rar. Pentru animații actualizate frecvent, folosiți LAYER_TYPE_NONE pentru a evita actualizarea costisitoare a stratului hardware. Profilați prin GPU Profile Rendering și Android Studio Profiler.

Întrebări frecvente

Se poate crea Canvas fără View?

Da, se poate crea Canvas(Bitmap) — un constructor care primește Bitmap. Aceasta se folosește pentru randarea offscreen: desenați pe Bitmap, apoi îl afișați prin drawBitmap(). Canvas poate fi creat și din Surface (pentru SurfaceView) sau prin Picture.

Cu ce diferă Canvas de SurfaceView?

Canvas — este API pentru desenarea pe View în firul UI. SurfaceView — este un Surface separat care poate fi actualizat din firul de fundal prin propriul Canvas (lockCanvas() / unlockCanvasAndPost()). SurfaceView este preferat pentru jocuri și video.

De ce Canvas nu desenează după transformare?

Cea mai frecventă cauză sunt save() și restore() dezechilibrate. Dacă după transformare (translate, rotate) nu se apelează restore(), Canvas rămâne în sistemul de coordonate modificat, iar elementele următoare sunt desenate cu deplasare. Verificați perechile save()/restore().

Cum să desenez textul în centrul Canvas?

Folosiți Paint.setTextAlign(Paint.Align.CENTER) pentru alinierea orizontală și Paint.getTextBounds() sau Paint.descent() / ascent() pentru verticală. Centrare: canvas.drawText(text, centerX, centerY - (ascent + descent) / 2, paint).

Suportă Canvas animația?

Canvas în sine nu animează — el doar desenează starea curentă. Animația se realizează prin apeluri succesive invalidate() (sau postInvalidateOnAnimation()), desenând de fiecare dată un nou cadru în onDraw(). Pentru animații line folosiți ValueAnimator sau Choreographer pentru sincronizarea cu Vsync.

Concluzii

  • Canvas — clasa centrală de desenare 2D în Android, oferă metode draw* pentru desenarea primitivelor, textului și imaginilor
  • Paint — definește stilul vizual (culoare, grosime, umplere, shadere); creat o dată și reutilizat
  • save() / restore() — gestionarea stivei de transformări; fiecare transformare trebuie să fie într-o pereche save/restore
  • Path — construirea de contururi arbitrare și curbe Bezier pentru grafică vectorială complexă
  • Offscreen Bitmap — tehnica de stocare a scenelor complexe prin Canvas(Bitmap) pentru reducerea încărcării onDraw()
  • Accelerarea Hardware — accelerare GPU pentru Canvas din Android 3.0, impune limitări pentru unele operații (clipPath)
  • Profilarea — GPU Profile Rendering și Android Studio Profiler sunt obligatorii pentru găsirea blocajelor în onDraw()

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și