Canvas Androidban — egy osztály az android.graphics csomagból, amely API-t biztosít a 2D rajzoláshoz View-n. A Canvas úgy működik, mint egy vászon, amelyre a fejlesztő geometriai alakzatokat, szöveget, képeket és útvonalakat rajzol különböző draw* metódusok segítségével. Az Android Developers Documentation (2025) szerint a Canvas a fő eszköz az egyedi rajzoláshoz Androidban, és a Paint osztállyal együtt használatos a stílusok és színek beállításához. Minden onDraw() hívás egy kész Canvas példányt kap, amely a nézet bitmap pufferéhez van kapcsolva.
Főbb pontok
Canvas — a központi 2D grafikai osztály Androidban, amely metódusokat biztosít a síkra rajzoláshoz. Minden Canvas egy Bitmap-hez van kapcsolva — egy memóriaterülethez, amelybe a rajzolási műveletek eredményei kerülnek. Amikor a View újrarajzolódik, a rendszer az onDraw()-nak egy Canvas-t ad át, amely már ehhez a View-hoz van kapcsolva.
A Canvas egy koordinátarendszerben működik, ahol (0,0) a bal felső sarok, az X tengely jobbra, az Y tengely lefelé mutat. Minden rajzolási művelet a Canvas aktuális állapotát használja, beleértve a transzformációs mátrixot, a vágási területet (clip) és a Paint stílust. Az Android Documentation (2025) szerint a Canvas API több mint 30 draw* metódust tartalmaz különböző típusú grafikai primitívekhez.
Android 3.0 (API 11) óta a Canvas támogatja a hardvergyorsítást a DisplayList segítségével. Gyorsított módban a Canvas műveletek a DisplayList-be íródnak, majd a GPU-n hajtódnak végre. Ez jelentős teljesítménynövekedést biztosít, de korlátozásokat vezet be: egyes Canvas műveletek (clipPath nem Path vágással) nem támogatottak gyorsított módban.
A Canvas metóduskészletet biztosít az alapvető primitívek rajzolásához. Minden metódus geometriai paramétereket és egy Paint objektumot fogad, amely meghatározza a vizuális stílust.
| Metódus | Cél | Példa |
|---|---|---|
| drawRect() | Téglalap rajzolása | canvas.drawRect(10f, 10f, 100f, 100f, paint) |
| drawCircle() | Kör rajzolása | canvas.drawCircle(50f, 50f, 30f, paint) |
| drawLine() | Vonal rajzolása | canvas.drawLine(0f, 0f, 100f, 100f, paint) |
| drawText() | Szöveg rajzolása | canvas.drawText("Hello", 10f, 20f, paint) |
| drawBitmap() | Kép rajzolása | canvas.drawBitmap(bitmap, 0f, 0f, paint) |
| drawPath() | Tetszőleges útvonal rajzolása | canvas.drawPath(path, paint) |
| drawOval() | Ovális rajzolása | canvas.drawOval(rectF, paint) |
| drawArc() | Ív vagy szektor rajzolása | canvas.drawArc(rectF, 0f, 90f, true, paint) |
Minden metódus tetszőleges sorrendben hívható — a Canvas a hívások sorrendjében rajzol, az új elemeket a korábbiak fölé helyezve. Összetett kompozíciókhoz a többrétegű rajzolás technikáját használják a Canvas állapotának mentésével és visszaállításával.
Paint — az az osztály, amely meghatározza, hogy a Canvas hogyan fog rajzolni. Paint nélkül a Canvas metódusai haszontalanok — beállítja a színt, vonalvastagságot, kitöltési stílust, szövegméretet, effekteket (árnyék, átmenet, elmosás) és keverési módot.
A Paint kulcsfontosságú tulajdonságai: color (szín), style (FILL, STROKE vagy FILL_AND_STROKE), strokeWidth (vonalvastagság), textSize (szövegméret), isAntiAlias (élsimítás), shader (átmenet vagy kép). A Paint objektum létrehozása költséges művelet, ezért egyszer kell létrehozni és újrahasználni.
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)
}
Ebben a példában két Paint van használatban: az egyik a kör lila színnel való kitöltéséhez, a másik a fehér körvonalhoz. A fill és stroke szétválasztása szokásos gyakorlat, amely lehetővé teszi a megjelenés rugalmas kezelését az objektumok újraalkotása nélkül.
Az átmenetes kitöltésekhez a Paint egy Shader-t fogad — a LinearGradient, RadialGradient, SweepGradient alosztályokat. A Shader a setShader() metódussal csatlakozik a Paint-hez, és meghatározza, hogy a szín hogyan változik a rajzolási területen.
A Canvas támogatja a koordinátarendszer mátrix transzformációit: translate() (eltolás), rotate() (forgatás), scale() (skálázás) és skew() (ferdítés). A transzformációk halmozódnak: minden következő hívás az előzőekre épül.
A transzformációs verem kezelése a save() és restore() segítségével történik. A save() elmenti a Canvas aktuális állapotát (mátrix, clip) a verembe, a restore() visszaállítja az utoljára mentett állapotot. A save() és restore() között beágyazott transzformációk lehetnek.
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.save() // Kezdeti állapot mentése
canvas.translate(100f, 100f) // Origó eltolása
// Első négyzet
canvas.drawRect(0f, 0f, 50f, 50f, fillPaint)
canvas.save() // Mentés eltolás után
canvas.rotate(45f, 25f, 25f) // Forgatás a négyzet középpontja körül
// Elforgatott négyzet
canvas.drawRect(0f, 0f, 50f, 50f, strokePaint)
canvas.restore() // Visszaállítás forgatás után
canvas.restore() // Kezdeti állapot visszaállítása
}
Mindig használjon save()-t a transzformációk megkezdése előtt és restore()-t a befejezésük után. A kiegyensúlyozatlan save/restore a mátrix felhalmozódásához és a későbbi elemek helytelen rajzolásához vezet.
Összetett grafikához a Canvas-t Bitmap-pel és Path-sal kombinálják. A Bitmap képek betöltésére és renderelt képkockák gyorsítótárazására szolgál. A Path — tetszőleges Bezier-görbék, sokszögek és összetett kontúrok építésére.
Offscreen-renderelés technikája: létrehoznak egy Bitmap-et, amelyre egy külön Canvas segítségével egy összetett jelenetet rajzolnak, majd a kész Bitmap-et az onDraw()-ban a drawBitmap()-en keresztül jelenítik meg. Ez lehetővé teszi az összetett grafika frissítését anélkül, hogy minden képkockát teljesen újrarajzolnának.
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)
// Jelenet renderelése egyszer
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 összetett kontúrok építésére szolgál: Bezier-görbék (quadTo, cubicTo), ívek (arcTo), vonalak (lineTo). A Path lehet zárt (close()) kitöltött alakzatokhoz vagy nyitott vonalakhoz. A drawPath() fő metódusok a Path-et és a Paint-et kombinálják a végső rajzoláshoz.
A Canvas rajzolás teljesítménye közvetlenül befolyásolja az alkalmazás FPS-ét. Fő problémák: túlzott foglalások az onDraw()-ban, gyakori invalidate() és a hardvergyorsítás nem optimális használata.
A Paint, Path, Rect, RectF és más objektumokat egyszer kell létrehozni az inicializátorban vagy a setup() metódusban. Minden foglalás az onDraw()-ban terheli a garbage collectort, ami mikro-akadásokhoz vezet. Kivétel — static vagy companion object immutable objektumokhoz.
Ha a View nagy része a látható területen kívül rejtőzik (pl. ScrollView-ben), használja a canvas.clipRect()-et a rajzolás korlátozásához. A hardvergyorsítás ebben az esetben tovább optimalizálja a láthatatlan pixelek levágását.
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// Vágás a látható területre
canvas.save()
canvas.clipRect(scrollX, scrollY, scrollX + width, scrollY + height)
// Nagy jelenet renderelése
renderScene(canvas)
canvas.restore()
}
Használja a View.setLayerType()-ot LAYER_TYPE_HARDWARE-val azon View-hoz, amely ritkán frissülő összetett Canvas grafikával rendelkezik. Gyakran frissülő animációkhoz használja a LAYER_TYPE_NONE-t, hogy elkerülje a hardverréteg költséges frissítését. Profilozzon a GPU Profile Rendering és Android Studio Profiler segítségével.
Gyakran Ismételt Kérdések
Igen, létrehozható Canvas(Bitmap) — egy konstruktor, amely Bitmap-et fogad. Ezt offscreen-rendereléshez használják: a Bitmap-re rajzolnak, majd a drawBitmap()-en keresztül jelenítik meg. A Canvas létrehozható Surface-ből (SurfaceView-hoz) vagy Picture-n keresztül is.
Canvas — API a View-ra rajzoláshoz az UI szálban. SurfaceView — egy külön Surface, amely a háttérszálból frissíthető saját Canvas segítségével (lockCanvas() / unlockCanvasAndPost()). A SurfaceView előnyösebb játékokhoz és videókhoz.
A leggyakoribb ok a kiegyensúlyozatlan save() és restore(). Ha a transzformáció (translate, rotate) után nem hívják meg a restore()-t, a Canvas a megváltozott koordinátarendszerben marad, és a későbbi elemek eltolással rajzolódnak. Ellenőrizze a save()/restore() párokat.
Használja a Paint.setTextAlign(Paint.Align.CENTER)-t vízszintes igazításhoz és a Paint.getTextBounds()-t vagy a Paint.descent() / ascent()-et függőleges igazításhoz. Középre igazítás: canvas.drawText(text, centerX, centerY - (ascent + descent) / 2, paint).
A Canvas önmagában nem animál — csak az aktuális állapotot rajzolja ki. Az animáció egymást követő invalidate() (vagy postInvalidateOnAnimation()) hívásokkal érhető el, minden alkalommal új képkockát rajzolva az onDraw()-ban. Sima animációkhoz használja a ValueAnimator-t vagy a Choreographer-t a Vsync-hez való szinkronizáláshoz.
Összefoglalás
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is