Canvas in Android — is een klasse uit het android.graphics-pakket die een API biedt voor 2D-tekening op View. Canvas werkt als een canvas waarop de ontwikkelaar geometrische figuren, tekst, afbeeldingen en paden tekent met behulp van verschillende draw*-methoden. Volgens Android Developers Documentation (2025) is Canvas het belangrijkste hulpmiddel voor aangepast tekenen in Android en wordt het samen met de Paint-klasse gebruikt voor het instellen van stijlen en kleuren. Elke aanroep van onDraw() ontvangt een kant-en-klare Canvas-instantie die is gekoppeld aan de bitmapbuffer van de view.
Belangrijkste punten
Canvas — is de centrale 2D-grafieklasse in Android die methoden biedt voor tekenen op een oppervlak. Elke Canvas is gekoppeld aan een Bitmap — een geheugengebied waarin de resultaten van tekenbewerkingen worden geschreven. Wanneer een View opnieuw wordt getekend, geeft het systeem een Canvas door aan onDraw() dat al is gekoppeld aan de buffer van deze View.
Canvas werkt in een coördinatensysteem waarbij (0,0) de linkerbovenhoek is, de X-as naar rechts gaat en de Y-as naar beneden. Alle tekenbewerkingen gebruiken de huidige status van Canvas, inclusief de transformatiematrix, het clipgebied (clip) en de Paint-stijl. Volgens Android Documentation (2025) omvat de Canvas API meer dan 30 draw*-methoden voor verschillende soorten grafische primitieven.
Sinds Android 3.0 (API 11) ondersteunt Canvas hardwareversnelling via DisplayList. In de versnelde modus worden Canvas-bewerkingen naar DisplayList geschreven en vervolgens op de GPU uitgevoerd. Dit geeft een aanzienlijke prestatieverbetering, maar legt beperkingen op: sommige Canvas-bewerkingen (clipPath met niet-Path-clip) worden niet ondersteund in de versnelde modus.
Canvas biedt een reeks methoden voor het tekenen van basisprimitieven. Elke methode ontvangt geometrische parameters en een Paint-object dat de visuele stijl bepaalt.
| Methode | Doel | Voorbeeld |
|---|---|---|
| drawRect() | Rechthoek tekenen | canvas.drawRect(10f, 10f, 100f, 100f, paint) |
| drawCircle() | Cirkel tekenen | canvas.drawCircle(50f, 50f, 30f, paint) |
| drawLine() | Lijn tekenen | canvas.drawLine(0f, 0f, 100f, 100f, paint) |
| drawText() | Tekst tekenen | canvas.drawText("Hello", 10f, 20f, paint) |
| drawBitmap() | Afbeelding tekenen | canvas.drawBitmap(bitmap, 0f, 0f, paint) |
| drawPath() | Willekeurig pad tekenen | canvas.drawPath(path, paint) |
| drawOval() | Ovaal tekenen | canvas.drawOval(rectF, paint) |
| drawArc() | Boog of sector tekenen | canvas.drawArc(rectF, 0f, 90f, true, paint) |
Elke methode kan in willekeurige volgorde worden aangeroepen — Canvas tekent in de volgorde van aanroepen, waarbij nieuwe elementen over vorige worden geplaatst. Voor complexe composities wordt de techniek van meerlaags tekenen met opslaan en herstellen van de Canvas-status gebruikt.
Paint — is de klasse die bepaalt hoe Canvas zal tekenen. Zonder Paint zijn Canvas-methoden nutteloos — het stelt kleur, lijndikte, vulstijl, tekstgrootte, effecten (schaduw, verloop, vervaging) en overvloeimodus in.
Paint heeft belangrijke eigenschappen: color (kleur), style (FILL, STROKE of FILL_AND_STROKE), strokeWidth (lijndikte), textSize (tekstgrootte), isAntiAlias (anti-aliasing), shader (verloop of afbeelding). Het maken van een Paint-object is een dure bewerking, dus moet het eenmaal worden gemaakt en hergebruikt.
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 dit voorbeeld worden twee Paint-objecten gebruikt: één voor het vullen van de cirkel met paars, de tweede voor de witte omtrek. De scheiding in fill en stroke is een standaardpraktijk die flexibel beheer van het uiterlijk mogelijk maakt zonder objecten opnieuw te maken.
Voor verloopvullingen accepteert Paint een Shader — subklassen LinearGradient, RadialGradient, SweepGradient. Shader wordt aan Paint gekoppeld via de methode setShader() en bepaalt hoe de kleur verandert over het tekengebied.
Canvas ondersteunt matrixtransformaties van het coördinatensysteem: translate() (verplaatsing), rotate() (rotatie), scale() (schaling) en skew() (scheeftrekken). Transformaties stapelen zich op: elke volgende aanroep wordt bovenop vorige toegepast.
Beheer van de transformatiestapel gebeurt via save() en restore(). save() slaat de huidige Canvas-status (matrix, clip) op in de stapel, restore() herstelt de laatst opgeslagen status. Tussen save() en restore() kunnen geneste transformaties voorkomen.
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.save() // Bewaar begintoestand
canvas.translate(100f, 100f) // Verplaats oorsprong
// Eerste vierkant
canvas.drawRect(0f, 0f, 50f, 50f, fillPaint)
canvas.save() // Bewaar na verplaatsing
canvas.rotate(45f, 25f, 25f) // Roteer rond midden vierkant
// Geroteerd vierkant
canvas.drawRect(0f, 0f, 50f, 50f, strokePaint)
canvas.restore() // Herstel na rotatie
canvas.restore() // Herstel begintoestand
}
Gebruik altijd save() vóór het begin van transformaties en restore() na voltooiing. Ongebalanceerde save/restore leiden tot ophoping van de matrix en incorrect tekenen van volgende elementen.
Voor complexe graphics wordt Canvas gecombineerd met Bitmap en Path. Bitmap wordt gebruikt voor het laden van afbeeldingen en het cachen van gerenderde frames. Path — voor het bouwen van willekeurige Bezier-curven, veelhoeken en complexe contouren.
Techniek van offscreen-rendering: er wordt een Bitmap gemaakt, waarop een complexe scène wordt getekend via een aparte Canvas, en vervolgens wordt de voltooide Bitmap weergegeven in onDraw() via drawBitmap(). Dit maakt het mogelijk complexe graphics bij te werken zonder elke frame volledig opnieuw te tekenen.
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 scène eenmalig
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 wordt gebruikt voor het bouwen van complexe contouren: Bezier-curven (quadTo, cubicTo), bogen (arcTo), lijnen (lineTo). Path kan gesloten zijn (close()) voor gevulde vormen of open voor lijnen. De belangrijkste methoden drawPath() combineren Path en Paint voor het uiteindelijke tekenen.
De prestaties van Canvas-tekening beïnvloeden direct de FPS van de applicatie. Belangrijkste problemen: overmatige allocaties in onDraw(), frequente invalidate() en suboptimaal gebruik van Hardware Acceleratie.
Paint, Path, Rect, RectF en andere objecten moeten eenmalig worden gemaakt in de initialisator of setup()-methode. Elke allocatie in onDraw() belast de garbage collector, wat leidt tot micro-hapers. Uitzondering — static of companion object voor immutable objecten.
Als een groot deel van de View verborgen is buiten het zichtbare gebied (bijv. in ScrollView), gebruik dan canvas.clipRect() om het tekenen te beperken. Hardware Acceleratie optimaliseert in dit geval extra het wegsnijden van onzichtbare pixels.
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// Knip naar zichtbaar gebied
canvas.save()
canvas.clipRect(scrollX, scrollY, scrollX + width, scrollY + height)
// Render grote scène
renderScene(canvas)
canvas.restore()
}
Gebruik View.setLayerType() met LAYER_TYPE_HARDWARE voor View met complexe Canvas-graphics die zelden wordt bijgewerkt. Voor vaak bijgewerkte animaties gebruik je LAYER_TYPE_NONE om dure updates van de hardwarelaag te voorkomen. Profileer via GPU Profile Rendering en Android Studio Profiler.
Veelgestelde vragen
Ja, je kunt Canvas(Bitmap) maken — een constructor die Bitmap accepteert. Dit wordt gebruikt voor offscreen-rendering: je tekent op Bitmap en geeft het vervolgens weer via drawBitmap(). Canvas kan ook worden gemaakt van Surface (voor SurfaceView) of via Picture.
Canvas — is een API voor tekenen op View in de UI-thread. SurfaceView — is een aparte Surface die kan worden bijgewerkt vanuit de achtergrondthread via zijn eigen Canvas (lockCanvas() / unlockCanvasAndPost()). SurfaceView heeft de voorkeur voor games en video.
De meest voorkomende oorzaak zijn ongebalanceerde save() en restore(). Als na transformatie (translate, rotate) geen restore() wordt aangeroepen, blijft Canvas in het gewijzigde coördinatensysteem en worden volgende elementen met verschuiving getekend. Controleer de save()/restore()-paren.
Gebruik Paint.setTextAlign(Paint.Align.CENTER) voor horizontale uitlijning en Paint.getTextBounds() of Paint.descent() / ascent() voor verticaal. Centrering: canvas.drawText(text, centerX, centerY - (ascent + descent) / 2, paint).
Canvas zelf animeert niet — het tekent alleen de huidige status. Animaties worden bereikt door opeenvolgende aanroepen van invalidate() (of postInvalidateOnAnimation()), waarbij elke keer een nieuw frame wordt getekend in onDraw(). Voor soepele animaties gebruik je ValueAnimator of Choreographer voor synchronisatie met Vsync.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook