Android-də Canvas — android.graphics paketindən olan, View-də 2D çəkmə üçün API təmin edən sinifdir. Canvas kətan kimi işləyir, üzərində tərtibatçı müxtəlif draw* metodları vasitəsilə həndəsi fiqurlar, mətn, şəkillər və yollar çəkir. Android Developers Documentation (2025) məlumatına görə, Canvas Android-də xüsusi çəkmə üçün əsas vasitədir və üslublar və rənglər təyin etmək üçün Paint sinfi ilə birlikdə istifadə olunur. Hər onDraw() çağırışı görünüşün bitmap buferi ilə əlaqəli hazır Canvas nümunəsi alır.
Əsas məqamlar
Canvas — Android-də mərkəzi 2D qrafika sinfidir, müstəvidə çəkmə üçün metodlar təmin edir. Hər Canvas Bitmap ilə əlaqəlidir — çəkmə əməliyyatlarının nəticələrinin yazıldığı yaddaş sahəsi. View yenidən çəkildikdə, sistem onDraw()-a bu View-in buferi ilə artıq əlaqəli Canvas ötürür.
Canvas koordinat sistemində işləyir, burada (0,0) yuxarı sol küncdür, X oxu sağa, Y oxu aşağı gedir. Bütün çəkmə əməliyyatları Canvas-ın cari vəziyyətindən, o cümlədən transformasiya matrisi, kəsmə sahəsi (clip) və Paint üslubundan istifadə edir. Android Documentation (2025) məlumatına görə, Canvas API müxtəlif qrafik primitivlər üçün 30-dan çox draw* metodu daxildir.
Android 3.0-dan (API 11) etibarən Canvas DisplayList vasitəsilə aparat sürətləndirilməsini dəstəkləyir. Sürətləndirilmiş rejimdə Canvas əməliyyatları DisplayList-ə yazılır və sonra GPU-da icra olunur. Bu, performansı əhəmiyyətli dərəcədə artırır, lakin məhdudiyyətlər qoyur: bəzi Canvas əməliyyatları (Path olmayan klip ilə clipPath) sürətləndirilmiş rejimdə dəstəklənmir.
Canvas əsas primitivlərin çəkilməsi üçün metodlar dəsti təmin edir. Hər metod həndəsi parametrlər və vizual üslubu təyin edən Paint obyektini qəbul edir.
| Metod | Məqsəd | Nümunə |
|---|---|---|
| drawRect() | Düzbucaqlı çəkmək | canvas.drawRect(10f, 10f, 100f, 100f, paint) |
| drawCircle() | Dairə çəkmək | canvas.drawCircle(50f, 50f, 30f, paint) |
| drawLine() | Xətt çəkmək | canvas.drawLine(0f, 0f, 100f, 100f, paint) |
| drawText() | Mətn çəkmək | canvas.drawText("Hello", 10f, 20f, paint) |
| drawBitmap() | Şəkil çəkmək | canvas.drawBitmap(bitmap, 0f, 0f, paint) |
| drawPath() | İxtiyari yol çəkmək | canvas.drawPath(path, paint) |
| drawOval() | Oval çəkmək | canvas.drawOval(rectF, paint) |
| drawArc() | Qövs və ya sektor çəkmək | canvas.drawArc(rectF, 0f, 90f, true, paint) |
Hər metod istənilən ardıcıllıqla çağrıla bilər — Canvas çağırış sırası ilə çəkir, yeni elementləri əvvəlkilərin üzərinə qoyur. Mürəkkəb kompozisiyalar üçün Canvas vəziyyətinin saxlanması və bərpası ilə çoxqatlı çəkmə texnikası istifadə olunur.
Paint — Canvas-ın necə çəkəcəyini təyin edən sinifdir. Paint olmadan Canvas metodları faydasızdır — o, rəng, xətt qalınlığı, doldurma üslubu, mətn ölçüsü, effektlər (kölgə, gradient, bulanıqlıq) və qarışdırma rejimini təyin edir.
Paint-in əsas xüsusiyyətləri: color (rəng), style (FILL, STROKE və ya FILL_AND_STROKE), strokeWidth (xətt qalınlığı), textSize (mətn ölçüsü), isAntiAlias (hamarlaşdırma), shader (gradient və ya şəkil). Paint obyektinin yaradılması bahalı əməliyyatdır, ona görə onu bir dəfə yaradıb təkrar istifadə etmək lazımdı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 nümunədə iki Paint istifadə olunur: biri dairəni bənövşəyi rənglə doldurmaq üçün, ikincisi ağ kontur üçün. Fill və stroke bölgüsü — obyektləri yenidən yaratmadan görünüşü çevik idarə etməyə imkan verən standart təcrübədir.
Gradient doldurmalar üçün Paint Shader qəbul edir — LinearGradient, RadialGradient, SweepGradient alt sinifləri. Shader setShader() metodu vasitəsilə Paint-ə bağlanır və rəngin çəkmə sahəsində necə dəyişdiyini təyin edir.
Canvas koordinat sisteminin matris çevrilmələrini dəstəkləyir: translate() (yerdəyişmə), rotate() (fırlanma), scale() (miqyaslama) və skew() (əymə). Transformasiyalar yığılır: hər növbəti çağırış əvvəlkilərin üzərinə tətbiq olunur.
Transformasiya yığınının idarə edilməsi save() və restore() vasitəsilə həyata keçirilir. save() Canvas-ın cari vəziyyətini (matris, clip) yığında saxlayır, restore() son saxlanmış vəziyyəti bərpa edir. save() və restore() arasında iç-içə transformasiyalar ola bilər.
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.save() // İlkin vəziyyəti saxla
canvas.translate(100f, 100f) // Mənşəyi yerdəyiş
// Birinci kvadrat
canvas.drawRect(0f, 0f, 50f, 50f, fillPaint)
canvas.save() // Yerdəyişmədən sonra saxla
canvas.rotate(45f, 25f, 25f) // Kvadrat mərkəzi ətrafında fırlat
// Fırlanmış kvadrat
canvas.drawRect(0f, 0f, 50f, 50f, strokePaint)
canvas.restore() // Fırlanmadan sonra bərpa et
canvas.restore() // İlkin vəziyyəti bərpa et
}
Həmişə transformasiyalara başlamazdan əvvəl save() istifadə edin və bitdikdən sonra restore() çağırın. Balanssız save/restore matrisin yığılmasına və sonrakı elementlərin səhv çəkilməsinə səbəb olur.
Mürəkkəb qrafika üçün Canvas Bitmap və Path ilə birləşdirilir. Bitmap şəkilləri yükləmək və render edilmiş kadrları keşləmək üçün istifadə olunur. Path — ixtiyari Bezier əyriləri, çoxbucaqlılar və mürəkkəb konturlar qurmaq üçün.
Offscreen-rendering texnikası: Bitmap yaradılır, üzərində ayrıca Canvas vasitəsilə mürəkkəb səhnə çəkilir və hazır Bitmap onDraw()-da drawBitmap() ilə göstərilir. Bu, hər kadrda tam yenidən çəkmədən mürəkkəb qrafikanı yeniləməyə imkan verir.
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)
// Səhnəni bir dəfə render et
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 mürəkkəb konturlar qurmaq üçün istifadə olunur: Bezier əyriləri (quadTo, cubicTo), qövslər (arcTo), xətlər (lineTo). Path doldurulmuş fiqurlar üçün bağlı (close()) və ya xətlər üçün açıq ola bilər. drawPath() əsas metodları son çəkmə üçün Path və Paint-i birləşdirir.
Canvas çəkməsinin performansı birbaşa tətbiqin FPS-nə təsir edir. Əsas problemlər: onDraw()-da həddindən artıq alokasiyalar, tez-tez invalidate() və Hardware Acceleration-dən optimal olmayan istifadə.
Paint, Path, Rect, RectF və digər obyektlər bir dəfə inisializatorda və ya setup() metodunda yaradılmalıdır. onDraw()-da hər alokasiya garbage collector-u yükləyir, bu da mikro-laglara səbəb olur. İstisna — immutable obyektlər üçün static və ya companion object.
View-in böyük hissəsi görünən sahədən kənarda gizlidirsə (məsələn, ScrollView-də), çəkməni məhdudlaşdırmaq üçün canvas.clipRect() istifadə edin. Bu halda Hardware Acceleration görünməyən piksellərin kəsilməsini əlavə olaraq optimallaşdırır.
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// Görünən sahəyə kəs
canvas.save()
canvas.clipRect(scrollX, scrollY, scrollX + width, scrollY + height)
// Böyük səhnəni render et
renderScene(canvas)
canvas.restore()
}
Nadir hallarda yenilənən mürəkkəb Canvas qrafikası olan View üçün View.setLayerType() LAYER_TYPE_HARDWARE ilə istifadə edin. Tez-tez yenilənən animasiyalar üçün isə LAYER_TYPE_NONE istifadə edin ki, aparat qatının bahalı yenilənməsindən qaçın. GPU Profile Rendering və Android Studio Profiler ilə profil edin.
Tez-tez verilən suallar
Bəli, Canvas(Bitmap) — Bitmap qəbul edən konstruktor yaratmaq olar. Bu, offscreen-rendering üçün istifadə olunur: Bitmap üzərində çəkirsiniz, sonra onu drawBitmap() vasitəsilə göstərirsiniz. Canvas həmçinin Surface-dən (SurfaceView üçün) və ya Picture vasitəsilə yaradıla bilər.
Canvas — UI thread-də View-də çəkmə üçün API-dir. SurfaceView — öz Canvas-ı (lockCanvas() / unlockCanvasAndPost()) vasitəsilə fon thread-indən yenilənə bilən ayrıca Surface-dir. SurfaceView oyunlar və video üçün üstünlük təşkil edir.
Ən çox rast gəlinən səbəb balanssız save() və restore()-dur. Əgər transformasiyadan (translate, rotate) sonra restore() çağırılmasa, Canvas dəyişdirilmiş koordinat sistemində qalır və sonrakı elementlər yerdəyişmə ilə çəkilir. save()/restore() cütlərini yoxlayın.
Üfüqi mərkəzləşdirmə üçün Paint.setTextAlign(Paint.Align.CENTER) və şaquli üçün Paint.getTextBounds() və ya Paint.descent() / ascent() istifadə edin. Mərkəzləşdirmə: canvas.drawText(text, centerX, centerY - (ascent + descent) / 2, paint).
Canvas özü animasiya etmir — o, yalnız cari vəziyyəti çəkir. Animasiya ardıcıl invalidate() (və ya postInvalidateOnAnimation()) çağırışları vasitəsilə əldə edilir, hər dəfə onDraw()-da yeni kadr çəkilir. Hamar animasiyalar üçün Vsync ilə sinxronizasiya üçün ValueAnimator və ya Choreographer istifadə edin.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun