onDraw() — bu nədir, çağırış mexanizmi və metodun override edilməsi

Müəllif: IT Sectr Dərc olunub: 2026-07-22 Oxuma vaxtı: 10 dəq

onDraw() — Android SDK-da View sinfinin əsas metodu olub, görünüşün məzmununun çəkilməsinə cavabdehdir. Sistem onDraw-ı View-in görünüşü hər yeniləndikdə çağırır — ilkin render zamanı, invalidate()-dan sonra və ya ölçülər dəyişdikdə. Android Developers Documentation (2026)-yə görə, Canvas API istifadə edərək onDraw-ı override etmək Android tətbiqlərində xüsusi qrafika yaratmağın əsas üsuludur.

Əsas məqamlar

  • onDraw(Canvas) — sistem tərəfindən Canvas-da məzmun çəkmək üçün çağırılan View metodu
  • invalidate() — növbəti frame dövründə onDraw çağırışına səbəb olan View-in yenidən çəkilməsi sorğusu
  • Canvas API drawCircle, drawBitmap, drawText, drawPath və digər çəkmə metodlarını təmin edir
  • Android sistemi çəkməni UI axınında yerinə yetirir, buna görə onDraw yüngül və sürətli olmalıdır
  • Hardware acceleration Android 3.0-dan (API 11) başlayaraq GPU vasitəsilə çəkməni avtomatik sürətləndirir

onDraw() nədir?

onDraw(Canvas canvas) — android.view.View sinfinin qorunan metodu olub, View render edilməli olduqda Android sistemi tərəfindən çağırılır. Tərtibatçı bu metodu xüsusi çəkməni həyata keçirmək üçün override edir: fiqurlar, mətn, şəkillər, gradientlər, animasiya. Canvas parametri bütün rəsm əməliyyatlarının yerinə yetirildiyi qrafik səthdir.

Metodun imzası sadədir: override fun onDraw(canvas: Canvas). Bu metodun daxilində yeni obyektlər yaratmaq (GC yükünün qarşısını almaq üçün), uzun əməliyyatlar yerinə yetirmək və ya şəbəkə ilə işləmək olmaz. View həmçinin öz həyat dövründə onLayout (mövqelərin hesablanması) və dispatchDraw (uşaq elementlərin çəkilməsi) arasında onDraw metodunu ehtiva edir.

View-dən vərəsəlik aldıqda hər hansı məzmunun göstərilməsi üçün onDraw-ı override etmək məcburidir — əks halda View boş olacaq. Mövcud alt siniflərdən (TextView, ImageView, Button) vərəsəlik aldıqda onDraw-ı override etmək isteğe bağlıdır və standart məzmun üzərində əlavə qrafika əlavə etmək üçün istifadə olunur.

View-in çəkmə dövrü

Android View-in çəkilməsini ciddi şəkildə müəyyən edilmiş ardıcıllıqla yerinə yetirir, bu ardıcıllıq əsas axından (UI thread) çağırılır. Tam dövr üç fazadan ibarətdir: measure (ölçülərin ölçülməsi), layout (mövqelərin hesablanması) və draw (çəkmə). onDraw draw fazasının bir hissəsidir və View-in ölçüləri və mövqeyi müəyyən edildikdən sonra çağırılır.

Draw fazası: dispatchDraw və onDraw

draw(Canvas canvas) — onDraw və dispatchDraw-ı çağıran View-in public metodudur. draw metodu override üçün nəzərdə tutulmayıb — onun əvəzinə onDraw override edilir. Cari View üçün onDraw icra edildikdən sonra dispatchDraw çağırılır, o da bütün uşaq View-lər üçün draw-ı rekursiv şəkildə çağırır (əgər cari View ViewGroup konteyneridirsə).

Sistem onDraw-ı nə vaxt çağırır

onDraw aşağıdakı şərtlər daxilində çağırılır: 1) View ilk dəfə görünən olur (setVisibility(VISIBLE)-dan sonra); 2) tətbiq bu View və ya onun valideyni üçün invalidate() çağırır; 3) View-in ölçüsü dəyişir (yeni layout); 4) View ilə əlaqəli animasiya dəyişir (ValueAnimator və ya ObjectAnimator vasitəsilə); 5) View-in vəziyyəti dəyişir (pressed, focused, enabled).

Apparat sürətləndirilməsi

Android 3.0 (API 11)-dan etibarən Canvas əməliyyatlarının əksəriyyəti GPU vasitəsilə aparat sürətləndirilməsi ilə yerinə yetirilir. Tərtibatçı sürətləndirmənin aktiv olub-olmadığını canvas.isHardwareAccelerated() vasitəsilə yoxlaya bilər. Apparat sürətləndirilməsi zamanı bəzi Canvas əməliyyatları dəstəklənmir (məsələn, düzbucaqlı olmayan sahə ilə clipPath) və nəzərə alınmaya və ya xətalara səbəb ola bilər.

Xüsusi qrafika üçün Canvas API

Canvas rəsm çəkmək üçün zəngin metodlar dəsti təqdim edir. Bütün metodlar cari koordinat sistemində işləyir, bu sistem transformasiyalar (translate, rotate, scale, skew) vasitəsilə dəyişdirilə bilər. Hər bir metod rəng, üslub, xətt qalınlığı, effektlər və hamarlaşdırmanı təyin edən Paint obyektini qəbul edir.

Canvas metoduMəqsədPaint-in əsas parametrləri
drawCircleDairə çəkməkcenterX, centerY, radius, paint
drawRectDüzbucaqlı çəkməkleft, top, right, bottom, paint
drawLineXətt çəkməkstartX, startY, endX, endY, paint
drawPathİxtiyari kontur çəkməkpath, paint
drawBitmapŞəkil çəkməkbitmap, srcRect, dstRect, paint
drawTextMətn çəkməktext, x, y, paint
drawArcQövs və ya sektor çəkməkovalRect, startAngle, sweepAngle, useCenter, paint
drawOvalOval çəkməkovalRect, paint

Paint obyekti

Paint çəkmə üslubunu təyin edir: rəng (setColor), xətt qalınlığı (setStrokeWidth), doldurma üslubu (setStyle — FILL, STROKE, FILL_AND_STROKE), hamarlaşdırma (setAntiAlias), effektlər (setShadowLayer, setMaskFilter) və gradientlər (setShader). Paint-in View konstruktorunda bir dəfə yaradılması və konfiqurasiya edilməsi tövsiyə olunur, onDraw daxilində deyil — bu, çəkmə dövründə obyekt yaradılmasının qarşısını alır.

Koordinatlar və transformasiyalar

Canvas koordinat sistemindən istifadə edir, burada X oxu sağa, Y oxu isə aşağıya yönəlmişdir. Koordinatların başlanğıcı (0, 0) View-in yuxarı sol küncüdür. draw metodlarını çağırmazdan əvvəl tərtibatçı koordinat sistemini canvas.translate(dx, dy), canvas.rotate(degrees, px, py), canvas.scale(sx, sy, px, py) vasitəsilə dəyişə bilər. Bütün sonrakı rəsm əməliyyatları transformasiya edilmiş sistemdə yerinə yetiriləcək.

onDraw performansı

onDraw əsas UI axınında icra olunur və onun müddəti birbaşa saniyədə kadr sayına (fps) təsir edir. 60 fps qorumaq üçün onDraw metodu 16 millisaniyədən çox olmayaraq tamamlanmalıdır. Hər hansı yavaşlama kadrların buraxılmasına (jank) gətirib çıxarır ki, bu da vizual olaraq animasiyanın ləngiməsi və ya sürüşdürmə zamanı gecikmə kimi qəbul edilir.

Məhsuldar onDraw qaydaları

Əsas qaydalar onDraw optimallaşdırılmasına daxildir: 1) onDraw daxilində obyekt yaratmayın — bütün Paint, Path, Rect sinif sahələri olmalıdır; 2) yaddaş ayırmayın (new) — bu, zibil yığıcını (GC) işə salır və kadrların buraxılmasına səbəb olur; 3) mürəkkəb əməliyyatları Bitmap.createBitmap vasitəsilə Bitmap-da keşləyin və hazır Bitmap-ı çəkin; 4) giriş-çıxış əməliyyatları və ya resursların yüklənməsini yerinə yetirməyin.

Optimallaşdırma üçün clipRect istifadəsi

clipRect çəkmə sahəsini müəyyən düzbucaqlı ilə məhdudlaşdırır. Canvas-ın görünən sahədən kənar piksellərin renderinə vaxt sərf etməməsi üçün istifadə olunur. Böyük siyahıların sürüşdürülməsi və ya miqyaslama zamanı xüsusilə effektivdir: clipRect-i görünən sahəyə (dirty rect) təyin edin və Canvas yalnız görünəni çəkəcək.

Layer — saxlama və bərpa

canvas.save() Canvas-ın cari vəziyyətini (transformasiya və clip) yığında saxlayır. canvas.restore() son saxlanmış vəziyyəti bərpa edir. Bu, müvəqqəti transformasiyalar üçün lazımdır: vəziyyəti saxlayırsınız, translate/rotate tətbiq edirsiniz, çəkirsiniz, sonra bərpa edirsiniz. save və restore yüngüldür və ağıllı istifadə zamanı (10–15 səviyyədən az iç-içəlik) performansa təsir etmir.

invalidate və postInvalidate

invalidate() — View-in məzmununun köhnəldiyini və yenidən çəkilməsi lazım olduğunu sistemə bildirən View metodudur. invalidate çağırışı onDraw-ın çağırılacağı yeni draw dövrünü başladır. invalidate yalnız UI axınından (main thread) çağırılmalıdır. Fon axınından çağırış üçün postInvalidate istifadə olunur.

postInvalidate() — invalidate-in thread-təhlükəsiz versiyasıdır, yenidən çəkmə sorğusunu Handler vasitəsilə əsas axının növbəsinə göndərir. Məlumat yükləməsi və ya hesablamalar tamamlandıqdan sonra View-i yeniləmək lazım olduqda fon tapşırıqlarında istifadə olunur. UI ilə sinxronizasiya üçün runOnUiThread ilə birləşdirilir.

Qismən yenidən çəkmə üçün invalidate(Rect dirty) və ya invalidate(int l, int t, int r, int b) istifadə olunur. Bu, sistemə yalnız müəyyən sahənin dəyişdiyini, bütün View-in deyil, göstərir. Android yalnız dirty rect-i yenidən çəkərək renderi optimallaşdırır ki, bu da qismən yeniləmələrlə animasiyalarda performansı əhəmiyyətli dərəcədə artırır.

Kotlin-də kod nümunələri

Praktik nümunələri nəzərdən keçirək — Kotlin-də Android üçün xüsusi View-lər yaratmaq üçün onDraw-ın override edilməsi.

Xüsusi View — dairəvi gedişat

Nümunə animasiyalı doldurma ilə dairəvi gedişat göstəricisi yaradır. onDraw iki dairə çəkir: boz fon rəngli və rəngli doldurulan, qövsü cari gedişatla müəyyən edilir. setProgress-da invalidate çağırışı dəyər dəyişdikdə yenidən çəkməni təmin edir.

kotlin
class CircularProgressView
    @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null
) : View(context, attrs) {

    private val bgPaint = Paint().apply {
        style = Paint.Style.STROKE
        strokeWidth = 12f
        color = Color.parseColor("#E0E0E0")
        isAntiAlias = true
    }

    private val progressPaint = Paint().apply {
        style = Paint.Style.STROKE
        strokeWidth = 12f
        color = Color.BLUE
        isAntiAlias = true
        strokeCap = Paint.Cap.ROUND
    }

    var progress: Float = 0f
        set(value) {
            field = value.coerceIn(0f, 1f)
            invalidate()
        }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val size = minOf(width, height) - 24f
        val oval = RectF(12f, 12f,
                          12f + size, 12f + size)

        canvas.drawArc(oval, 270f, 360f, false, bgPaint)
        canvas.drawArc(oval, 270f,
                        progress * 360f,
                        false, progressPaint)
    }
}

Xüsusi View — gradient fonlu mətn

Nümunə üzərində mətn olan gradient düzbucaqlı çəkir. Gradient LinearGradient (Shader) vasitəsilə, mətn isə drawText vasitəsilə yaradılır. Hər iki Paint konstruktorda bir dəfə yaradılır, onDraw-da isə yalnız düzbucaqlının ölçüsü cari View enindən asılı olaraq dəyişdirilir.

kotlin
class GradientTextView(context: Context)
    : View(context) {

    private val shaderPaint = Paint().apply {
        isAntiAlias = true
    }

    private val textPaint = Paint().apply {
        color = Color.WHITE
        textSize = 48f
        isAntiAlias = true
        textAlign = Paint.Align.CENTER
    }

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

        val gradient = LinearGradient(
            0f, 0f, width.toFloat(), 0f,
            Color.parseColor("#FF6B35"),
            Color.parseColor("#FF0040"),
            Shader.TileMode.CLAMP
        )
        shaderPaint.shader = gradient
        canvas.drawRect(0f, 0f,
                        width.toFloat(),
                        height.toFloat(), shaderPaint)

        val xCenter = width / 2f
        val yCenter = height / 2f
        val yOffset = (textPaint.descent() +
                        textPaint.ascent()) / 2f

        canvas.drawText("Canvas-dan salam",
                      xCenter, yCenter - yOffset,
                      textPaint)
    }
}

invalidate istifadə edərək animasiyalı saat

Nümunə hər 1000 millisaniyədən bir çəkməni yeniləyən animasiyalı saat yaradır. onDraw-da postDelayed bir saniyədən sonra invalidate çağıraraq sonsuz yenidən çəkmə dövrü yaradır. Saat əqrəbləri müxtəlif uzunluq və qalınlıqla drawLine vasitəsilə çəkilir.

kotlin
class AnalogClockView(context: Context)
    : View(context) {

    private val handPaint = Paint().apply {
        style = Paint.Style.STROKE
        isAntiAlias = true
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val cx = width / 2f
        val cy = height / 2f
        val radius = minOf(cx, cy) - 20f

        val now = Calendar.getInstance()
        val hours = now.get(Calendar.HOUR) % 12
        val minutes = now.get(Calendar.MINUTE)
        val seconds = now.get(Calendar.SECOND)

        val secondAngle = Math.toRadians(
            seconds * 6f - 90f)
        handPaint.strokeWidth = 2f
        handPaint.color = Color.RED
        canvas.drawLine(cx, cy,
            cx + cos(secondAngle) * radius * 0.8f,
            cy + sin(secondAngle) * radius * 0.8f,
            handPaint)

        postDelayed({ invalidate() }, 1000)
    }
}

Tez-tez verilən suallar

onDraw-ı birbaşa çağırmaq olar?

Xeyr, onDraw-ı birbaşa çağırmaq olmaz. Yenidən çəkmə sorğusu üçün invalidate() (UI axınından) və ya postInvalidate() (fon axınından) istifadə edin. Sistem özü onDraw-ın nə vaxt çağırılacağına qərar verir və çoxsaylı invalidate-ləri bir keçiddə birləşdirərək renderi optimallaşdırır.

Niyə onDraw invalidate-dan sonra çağırılmır?

Səbəblər: View gizlidir (setVisibility(GONE) və ya INVISIBLE); View Window iyerarxiyasına əlavə edilməyib; View-in ölçüsü 0-dır (width və ya height = 0); setWillNotDraw(true) çağırılır (ViewGroup üçün susmaya görə true). Debug zamanı bu maddələrin hər birini yoxlayın.

onDraw nə qədər tez-tez çağırıla bilər?

60 fps-də onDraw saniyədə 60 dəfəyə qədər çağırıla bilər. 120 fps-də (120 Hz displeyli cihazlarda) — 120 dəfəyə qədər. Hər çağırış ~8–16 millisaniyəyə tamamlanmalıdır. ObjectAnimator və ya ValueAnimator vasitəsilə aktiv animasiyalar zamanı tezlik animasiya kadrlarının sayı ilə müəyyən edilir.

onDraw və dispatchDraw arasında nə fərq var?

onDraw View-in öz məzmununun çəkilməsinə cavabdehdir. dispatchDraw uşaq View-lərin çəkilməsinə cavabdehdir (ViewGroup-da). dispatchDraw onDraw-dan sonra çağırılır və bütün uşaq elementləri rekursiv şəkildə gəzir. Adi View (ViewGroup deyil) üçün dispatchDraw boşdur.

Canvas-dan onDraw xaricində istifadə etmək olar?

Bəli, Canvas Canvas(bitmap) vasitəsilə Bitmap üçün yaradıla bilər və istənilən axında çəkmək olar. Bu, mürəkkəb qrafikanın fonda əvvəlcədən hesablanması üçün istifadə olunur. Lakin onDraw-da ötürülən Canvas sistemə məxsusdur və yalnız UI axınında onDraw metodu daxilində istifadə edilə bilər.

Nəticə

  • onDraw(Canvas) — Android-də Canvas API istifadə edərək xüsusi çəkmə üçün View-in əsas metodu
  • Çəkmə dövrü measure, layout və draw fazalarından ibarətdir — onDraw draw fazasında çağırılır
  • Canvas API drawCircle, drawRect, drawPath, drawBitmap, drawText və digər metodları ehtiva edir
  • invalidate() UI axınından, postInvalidate() isə fon axınından yenidən çəkmə sorğusu göndərir
  • Qismən yenidən çəkmə invalidate(Rect) vasitəsilə renderi optimallaşdıraraq yalnız dirty-sahəni yeniləyir
  • onDraw performansı kritikdir: metod daxilində obyekt yaratmaq GC və kadr buraxılmasına səbəb olur
  • Apparat sürətləndirilməsi (API 11-dən) GPU vasitəsilə Canvas əməliyyatlarını avtomatik sürətləndirir

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.

Layihəni müzakirə et

Həm də oxuyun