Android’de Canvas — android.graphics paketinden, View üzerinde 2B işleme için API sağlayan bir sınıftır. Canvas, geliştiricinin çeşitli draw* yöntemlerini kullanarak geometrik şekiller, metin, görüntüler ve yollar çizdiği bir tuval gibi çalışır. Android Geliştirici Dokümantasyonu’na (2025) göre Canvas, Android’de özel işleme için birincil araçtır ve stilleri ve renkleri tanımlamak için Paint sınıfıyla birlikte kullanılır. Her onDraw() çağrısı, görünümün bitmap arabelleğiyle ilişkili hazır bir Canvas örneği alır.
Önemli Noktalar
Canvas — Android’de bir düzlem üzerinde çizim yapmak için yöntemler sağlayan merkezi 2B grafik sınıfıdır. Her Canvas bir Bitmap’e bağlıdır — çizim işlemlerinin sonuçlarının kaydedildiği bir bellek alanı. Bir View yeniden çizildiğinde, sistem onDraw()’a bu View’ın arabelleğiyle zaten ilişkilendirilmiş bir Canvas iletir.
Canvas, (0,0)’ın sol üst köşe olduğu, X ekseninin sağa, Y ekseninin aşağı gittiği bir koordinat sisteminde çalışır. Tüm çizim işlemleri, dönüşüm matrisi, kırpma alanı ve Paint stili dahil olmak üzere Canvas’ın mevcut durumunu kullanır. Android Dokümantasyonu’na (2025) göre Canvas API, farklı grafik ilkel türleri için 30’dan fazla draw* yöntemi içerir.
Android 3.0 (API 11)’den itibaren Canvas, DisplayList aracılığıyla donanım hızlandırmasını destekler. Hızlandırılmış modda, Canvas işlemleri bir DisplayList’e kaydedilir ve ardından GPU’da yürütülür. Bu, önemli bir performans artışı sağlar ancak sınırlamalar getirir: bazı Canvas işlemleri (Path olmayan kırpma ile clipPath) hızlandırılmış modda desteklenmez.
Canvas, temel ilkelleri çizmek için bir dizi yöntem sağlar. Her yöntem, geometrik parametreleri ve görsel stili tanımlayan bir Paint nesnesini kabul eder.
| Yöntem | Amaç | Örnek |
|---|---|---|
| drawRect() | Dikdörtgen çizer | canvas.drawRect(10f, 10f, 100f, 100f, paint) |
| drawCircle() | Daire çizer | canvas.drawCircle(50f, 50f, 30f, paint) |
| drawLine() | Çizgi çizer | canvas.drawLine(0f, 0f, 100f, 100f, paint) |
| drawText() | Metin çizer | canvas.drawText(“Hello”, 10f, 20f, paint) |
| drawBitmap() | Görüntü çizer | canvas.drawBitmap(bitmap, 0f, 0f, paint) |
| drawPath() | İsteğe bağlı bir yol çizer | canvas.drawPath(path, paint) |
| drawOval() | Oval çizer | canvas.drawOval(rectF, paint) |
| drawArc() | Yay veya dilim çizer | canvas.drawArc(rectF, 0f, 90f, true, paint) |
Her yöntem herhangi bir sırayla çağrılabilir — Canvas, çağrı sırasına göre çizer ve yeni öğeleri öncekilerin üzerine yerleştirir. Karmaşık kompozisyonlar için, Canvas durumunu kaydetme ve geri yüklemeyle çok katmanlı işleme tekniği kullanılır.
Paint — Canvas’ın nasıl çizeceğini tanımlayan sınıftır. Paint olmadan Canvas yöntemleri işe yaramaz — rengi, çizgi kalınlığını, dolgu stilini, metin boyutunu, efektleri (gölge, gradyan, bulanıklık) ve karıştırma modunu ayarlar.
Paint’in temel özellikleri: color (renk), style (FILL, STROKE veya FILL_AND_STROKE), strokeWidth (çizgi kalınlığı), textSize (metin boyutu), isAntiAlias (kenar yumuşatma), shader (gradyan veya görüntü). Bir Paint nesnesi oluşturmak pahalı bir işlemdir, bu nedenle bir kez oluşturulup yeniden kullanılmalıdır.
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)
}
Bu örnekte, iki Paint nesnesi kullanılır: biri daireyi mor renkle doldurmak için, ikincisi beyaz kontur için. Dolgu ve konturu ayırmak, nesneleri yeniden oluşturmadan görünüm üzerinde esnek kontrol sağlayan standart bir uygulamadır.
Gradyan dolgular için Paint bir Shader kabul eder — alt sınıflar LinearGradient, RadialGradient, SweepGradient. Shader, setShader() yöntemi aracılığıyla Paint’e bağlanır ve rengin çizim alanı boyunca nasıl değiştiğini tanımlar.
Canvas, koordinat sisteminin matris dönüşümlerini destekler: translate() (öteleme), rotate() (döndürme), scale() (ölçekleme) ve skew() (eğme). Dönüşümler birikir: sonraki her çağrı öncekilerin üzerine uygulanır.
Dönüşüm yığınının yönetimi save() ve restore() aracılığıyla yapılır. save() geçerli Canvas durumunu (matris, kırpma) yığına kaydeder, restore() en son kaydedilen durumu geri yükler. save() ve restore() arasında iç içe dönüşümler uygulanabilir.
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
}
Dönüşümlere başlamadan önce her zaman save() ve bunları tamamladıktan sonra restore() kullanın. Dengesiz save/restore çiftleri, matris birikimine ve sonraki öğelerin yanlış işlenmesine yol açar.
Karmaşık grafikler için Canvas, Bitmap ve Path ile birleştirilir. Bitmap, görüntüleri yüklemek ve işlenmiş kareleri önbelleğe almak için kullanılır. Path, isteğe bağlı Bezier eğrileri, çokgenler ve karmaşık konturlar oluşturmak için kullanılır.
Ekran dışı işleme tekniği: bir Bitmap oluşturulur, üzerine ayrı bir Canvas aracılığıyla karmaşık bir sahne çizilir ve ardından tamamlanan Bitmap, drawBitmap() aracılığıyla onDraw() içinde görüntülenir. Bu, her karede tamamen yeniden çizmeden karmaşık grafikleri güncellemeye olanak tanır.
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, karmaşık konturlar oluşturmak için kullanılır: Bezier eğrileri (quadTo, cubicTo), yaylar (arcTo), çizgiler (lineTo). Path, dolu şekiller için kapatılabilir (close()) veya çizgiler için açık olabilir. Ana drawPath() yöntemi, son işleme için Path ve Paint’i birleştirir.
Canvas işleme performansı, uygulama FPS’sini doğrudan etkiler. Ana sorunlar: onDraw() içinde aşırı ayırmalar, sık invalidate() çağrıları ve Donanım Hızlandırması’nın optimal olmayan kullanımı.
Paint, Path, Rect, RectF ve diğer nesneler, başlatıcıda veya setup() yönteminde bir kez oluşturulmalıdır. onDraw() içindeki her ayırma, çöp toplayıcı üzerinde baskı oluşturarak mikro gecikmelere yol açar. İstisna, değiştirilemez nesneler için static veya companion object’dir.
View’ın çoğu görünür alanın dışında gizliyse (örneğin ScrollView içinde), işlemeyi sınırlamak için canvas.clipRect() kullanın. Donanım Hızlandırması bu durumda görünmeyen piksellerin kırpılmasını ek olarak optimize eder.
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()
}
Seyrek güncellenen karmaşık Canvas grafiklerine sahip View’lar için LAYER_TYPE_HARDWARE ile View.setLayerType() kullanın. Sık güncellenen animasyonlar için, pahalı donanım katmanı güncellemelerini önlemek için LAYER_TYPE_NONE kullanın. GPU Profile Rendering ve Android Studio Profiler ile profil oluşturun.
Sıkça Sorulan Sorular
Evet, Canvas(Bitmap) oluşturabilirsiniz — bir Bitmap kabul eden bir yapıcı. Bu, ekran dışı işleme için kullanılır: Bir Bitmap üzerinde çizer ve ardından drawBitmap() aracılığıyla görüntülersiniz. Canvas ayrıca Surface’dan (SurfaceView için) veya Picture aracılığıyla oluşturulabilir.
Canvas — UI iş parçacığında View üzerinde çizim için bir API’dir. SurfaceView — kendi Canvas’ı (lockCanvas() / unlockCanvasAndPost()) aracılığıyla bir arka plan iş parçacığından güncellenebilen ayrı bir Surface’dır. SurfaceView, oyunlar ve video için tercih edilir.
En yaygın neden, dengesiz save() ve restore() çiftleridir. Bir dönüşümden (translate, rotate) sonra restore() çağrılmazsa, Canvas değiştirilmiş bir koordinat sisteminde kalır ve sonraki öğeler ofsetle çizilir. save()/restore() çiftlerinizi kontrol edin.
Yatay ortalama için Paint.setTextAlign(Paint.Align.CENTER) ve dikey için Paint.getTextBounds() veya Paint.descent() / ascent() kullanın. Ortalama: canvas.drawText(metin, centerX, centerY - (ascent + descent) / 2, paint).
Canvas’ın kendisi animasyon yapmaz — yalnızca mevcut durumu çizer. Animasyon, her seferinde onDraw() içinde yeni bir kare çizerek invalidate() (veya postInvalidateOnAnimation()) ardışık çağrılarıyla elde edilir. Pürüzsüz animasyonlar için Vsync ile senkronize olmak üzere ValueAnimator veya Choreographer kullanın.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun