dispatchDraw(): bu nima, chaqirish mexanizmi va onDraw-dan farqi

Muallif: IT Sectr Nashr etilgan: 2026-07-22 O'qish vaqti: 9 daq

dispatchDraw() — bu Android iyerarxiyasidagi barcha bolaviy View-larni rekursiv chizish uchun mas'ul bo'lgan ViewGroup sinfining metodi. Android Developers Documentation (2026) ma'lumotlariga ko'ra, dispatchDraw asosiy View-ning draw() metodida onDraw-dan so'ng avtomatik ravishda chaqiriladi va barcha bolaviy elementlardan o'tib, ularning o'z draw() metodini chaqiradi. Dasturchilar maxsus ViewGroup-larda effektlarni qo'shish, bolalar ustiga grafika qo'yish yoki chizish tartibini o'zgartirish uchun dispatchDraw-ni qayta belgilaydilar.

Asosiy ma'lumotlar

  • dispatchDraw(Canvas canvas) — bolaviy View-larni chizish uchun onDraw-dan so'ng chaqiriladigan ViewGroup-ning protected metodi
  • draw(Canvas canvas) — ketma-ket onDraw, dispatchDraw va onDrawForeground-ni chaqiradigan View-ning public final metodi
  • onDraw View-ning o'z mazmunini chizadi, dispatchDraw esa — barcha bolaviy elementlarning mazmunini
  • setWillNotDraw(true) — faqat bolaviy elementlarni chizadigan, o'z mazmunini chizmaydigan ViewGroup uchun optimallashtirish
  • dispatchDraw-ni qayta belgilash effektlar (blur, overlay) yoki bolaviy elementlarni chizish animatsiyasi uchun ishlatiladi

dispatchDraw() nima?

dispatchDraw(Canvas canvas) — bu Android tizimi joriy konteynerning barcha bolaviy View-larini chizish uchun chaqiradigan ViewGroup sinfining protected metodi. dispatchDraw standart draw konveyerining bir qismidir: avval onDraw (View-ning o'z mazmunini chizish), keyin dispatchDraw (bolalarning rekursiv chizilishi), so'ngra onDrawForeground (foreground va scrollbars chizilishi) bajariladi. Metod ilova kodidan to'g'ridan-to'g'ri chaqirish uchun mo'ljallanmagan.

ViewGroup-dagi standart dispatchDraw amalga oshirilishi barcha bolaviy View-larni aylanib o'tadi, ularning ko'rinishini tekshiradi va har biri uchun draw(Canvas) chaqiradi. Aylanib o'tish tartibi bolalarning indekslariga mos keladi (0 dan childCount - 1 gacha). Agar bolaviy View-lar bir-birining ustiga tushsa, ro'yxatdagi oxirgilari birinchilarning ustida chiziladi. dispatchDraw-da tartibni o'zgartirish orqali Z-order chizish tartibini o'zgartirish mumkin.

View (ViewGroup emas) uchun dispatchDraw metodi bo'sh — oddiy View bolaviy elementlarga ega emas, shuning uchun chizadigan narsa yo'q. Metod View sinfida mavjud, lekin faqat ViewGroup nusxalarida chaqiriladi. Dasturchi View-da bolaviy elementlar bor-yo'qligini dispatchDraw-ning standart xatti-harakati orqali tekshirishi mumkin, lekin ko'pincha instanceof ViewGroup tekshirish osonroq.

Chizish konveyeri: onDraw, dispatchDraw, onDrawForeground

draw(Canvas) metodi View sinfining uch bosqichli chizish konveyerini tashkil qiladi. Birinchi bosqich — View o'z mazmunini chizadigan onDraw(canvas) chaqiruvi. Ikkinchi bosqich — bolaviy View-larni chizishni boshlaydigan dispatchDraw(canvas) chaqiruvi. Uchinchi bosqich — foreground qatlami, scrollbars va ripple effektlari uchun mas'ul bo'lgan onDrawForeground(canvas). Bu ketma-ketlik grafik qatlamlarning to'g'ri joylashish tartibini kafolatlaydi.

onDraw har doim dispatchDraw-dan oldin bajariladi. Bu degani, ota-ona View-ning mazmuni bolaviy View-lar ostida ko'rsatiladi. Agar bolalar ustida biror narsa chizish kerak bo'lsa, bu onDrawForeground-da yoki super.dispatchDraw(canvas) chaqiruvi bilan qayta belgilangan dispatchDraw-da amalga oshiriladi. Fon (background) onDraw-dan oldin — draw() metodi ichidagi drawBackground(canvas) da chiziladi.

Uskuna tezlashtirish (hardware acceleration) vaqtida draw konveyeri GPU orqali ishlaydi. View DisplayList-da — keshlangan va qayta ishlatiladigan chizish buyruqlari ro'yxatida chiziladi. Uskuna bilan tezlashtirilgan rejimda dispatchDraw bolaviy View-larning DisplayList-ni sahnaning umumiy DisplayList-ga qo'shadi. dispatchDraw-ni o'zgartirish DisplayList-ni bekor qilishga va keshnii qayta qurishga olib kelishi mumkin, bu esa ishlashga ta'sir qiladi.

MetodChaqirish tartibiMaqsad
drawBackground1Fonni chizish (background drawable)
onDraw2View-ning o'z mazmunini chizish
dispatchDraw3Barcha bolaviy View-larni chizish (faqat ViewGroup uchun)
onDrawForeground4Foreground, scrollbar va ripple effektini chizish

dispatchDraw onDraw-dan nimasi bilan farqlanadi

onDraw View-ning o'z mazmunini — shakllar, matn, tasvirlarni chizish uchun javobgardir. dispatchDraw bolaviy View-larni — ViewGroup ichidagi barcha elementlarni chizish uchun javobgardir. Agar ViewGroup dispatchDraw-ni qayta belgilamasa, ViewGroup-dan standart amalga oshirish ishlatiladi, u oddiygina childCount bo'ylab rekursiv o'tadi va har bir bola uchun draw chaqiradi.

O'z mazmunini chizmaydigan ViewGroup (masalan, FrameLayout, LinearLayout) uchun onDraw setWillNotDraw(true) o'rnatish orqali optimallashtirilishi mumkin. Bu holda onDraw hech qachon chaqirilmaydi, bu resurslarni tejaydi. dispatchDraw esa ishlashda davom etadi va bolaviy elementlar uchun draw chaqiradi. Barcha standart ViewGroup-lar (LinearLayout, RelativeLayout, ConstraintLayout) setWillNotDraw(true) dan foydalanadi.

Agar dispatchDraw super.dispatchDraw(canvas) chaqiruvisiz qayta belgilansa, bolaviy View-lar chizilmaydi. Bu barcha bolalarni vaqtincha yashirish uchun foydali bo'lishi mumkin, lekin ko'p hollarda xatolarga sabab bo'ladi. Tavsiya etilgan amaliyot: qayta belgilangan metodning boshida super.dispatchDraw(canvas) chaqiring, so'ngra bolalar ustiga o'z grafikingizni (masalan, alfa kanali bilan overlay) qo'shing.

Kotlin-da dispatchDraw-ni qayta belgilash namunasi

OverlayViewGroup yaratamiz — barcha bolaviy View-lar ustiga matn yorlig'i bilan yarim shaffof qatlam qo'shadigan maxsus ViewGroup. dispatchDraw avval super-ni chaqiradi (barcha bolalarni chizish), so'ngra overlay to'rtburchak va matnni chizadi. Paint draw siklida ajratmalarning oldini olish uchun konstruktorda yaratiladi.

kotlin
class OverlayViewGroup(context: Context)
    : ViewGroup(context) {

    private val overlayPaint = Paint().apply {
        color = Color.parseColor("#66000000")
        style = Paint.Style.FILL
    }

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

    init {
        setWillNotDraw(false)
    }

    override fun dispatchDraw(canvas: Canvas) {
        super.dispatchDraw(canvas)
        canvas.drawRect(0f, 0f,
                        width.toFloat(),
                        height.toFloat(), overlayPaint)
        canvas.drawText("KO'RISH REJIMI",
            width / 2f,
            height / 2f, textPaint)
    }

    override fun onLayout(changed: Boolean,
                       l: Int, t: Int,
                       r: Int, b: Int) {
        var top = t
        for (i in 0 until childCount) {
            val child = getChildAt(i)
            val cw = child.measuredWidth
            val ch = child.measuredHeight
            child.layout(l, top, l + cw, top + ch)
            top += ch
        }
    }

    override fun onMeasure(widthMeasureSpec: Int,
                       heightMeasureSpec: Int) {
        measureChildren(widthMeasureSpec, heightMeasureSpec)
        val maxWidth = resolveSize(
            getChildAt(0).measuredWidth,
            widthMeasureSpec)
        var totalHeight = 0
        for (i in 0 until childCount) {
            totalHeight += getChildAt(i).measuredHeight
        }
        setMeasuredDimension(maxWidth,
            resolveSize(totalHeight, heightMeasureSpec))
    }
}

dispatchDraw orqali animatsiyalangan Z-order

Keyingi misol bolaviy elementlarni chizish tartibini o'zgartirishni ko'rsatadi. CircularRevealLayout dispatchDraw-ni qayta belgilaydi va bolalarni teskari tartibda chizadi, teskari Z-order effektini yaratadi. Animatsiya uchun offset-ning animatsiya qiymatiga asoslangan chizish indeksining tsiklik siljishi qo'shiladi.

kotlin
class ReverseOrderLayout(context: Context)
    : ViewGroup(context) {

    private var reverse = false

    override fun dispatchDraw(canvas: Canvas) {
        if (!reverse) {
            super.dispatchDraw(canvas)
            return
        }
        for (i in childCount - 1 downTo 0) {
            val child = getChildAt(i)
            if (child.visibility == GONE) continue
            drawChild(canvas, child, getDrawingTime())
        }
    }

    fun toggleReverse() {
        reverse = !reverse
        invalidate()
    }

    override fun onLayout(changed: Boolean,
                       l: Int, t: Int,
                       r: Int, b: Int) {
        var left = l
        for (i in 0 until childCount) {
            val child = getChildAt(i)
            val cw = child.measuredWidth
            child.layout(left, t,
                left + cw, t + child.measuredHeight)
            left += cw
        }
    }

    override fun onMeasure(widthMeasureSpec: Int,
                       heightMeasureSpec: Int) {
        measureChildren(widthMeasureSpec, heightMeasureSpec)
        var totalWidth = 0
        for (i in 0 until childCount) {
            totalWidth += getChildAt(i).measuredWidth
        }
        setMeasuredDimension(
            resolveSize(totalWidth, widthMeasureSpec),
            resolveSize(getChildAt(0).measuredHeight,
                heightMeasureSpec))
    }
}

Android-da dispatchDraw qachon ishlatilishi kerak

dispatchDraw ViewGroup-ning o'z mazmuniga ta'sir qilmasdan bolaviy View-larni chizish jarayoniga ta'sir qilish kerak bo'lgan stsenariylarda ishlatiladi. Asosiy stsenariylar: barcha bolalar ustiga umumiy effekt (overlay, shadow, gradient) qo'yish; chuqurlik effektini yaratish uchun Z-order tartibini o'zgartirish; Canvas transformatsiyalari orqali bolaviy elementlarning paydo bo'lish yoki yo'qolish animatsiyasi.

Agar grafika bolaviy elementlar ostiga qo'yilishi kerak bo'lsa (fon effekti), onDraw ishlatilishi kerak — dispatchDraw undan keyin chaqiriladi. Agar grafika bolalar ustida bo'lishi kerak bo'lsa — super chaqiruvi bilan dispatchDraw, so'ngra Canvas.draw ishlating. Global rang yoki shaffoflik o'zgarishi kerak bo'lsa, bolalarni chizishni o'rab olgan dispatchDraw-da canvas.saveLayerAlpha() dan foydalanish qulay.

Tavsiya etilmaydi dispatchDraw-dan quyidagilar uchun foydalanish: 1) real-time murakkab animatsiyani chizish (invalidate va onDraw dan foydalaning); 2) ViewGroup-ning ekran tasvirlarini yaratish (buildDrawingCache() yoki View.draw(Canvas) dan foydalaning); 3) bolaviy View-larni o'zgartirish (koordinatalar, o'lchamlar — bu onLayout vazifasi, dispatchDraw emas). dispatchDraw — faqat vizual effektlarni qo'llash uchun.

Tez-tez beriladigan savollar

dispatchDraw-ni tizimsiz to'g'ridan-to'g'ri chaqirish mumkinmi?

Yo'q, dispatchDraw — Android tizimi tomonidan public draw() metodi ichida chaqiriladigan protected metod. dispatchDraw-ni to'g'ridan-to'g'ri chaqirishning ma'nosi yo'q, chunki u tayyorgarlik harakatlarini (Canvas-ni saqlash, fon va foreground chizish) bajarmaydi. Buning o'rniga ixtiyoriy Canvas-da dasturiy chizish uchun View.draw(Canvas) dan foydalaning.

Maxsus chizishdan so'ng super.dispatchDraw chaqirilsa nima bo'ladi?

O'z chizish operatsiyalaringizdan so'ng super.dispatchDraw(canvas) chaqirsangiz, bolaviy View-lar maxsus grafika ustida chiziladi. Bu qatlamlarning joylashishini o'zgartiradi: avval maxsus qatlam, keyin bolalar chiziladi. Agar teskari holat kerak bo'lsa (grafika bolalar ustida), avval super.dispatchDraw, so'ngra o'z operatsiyalaringizni chaqiring.

dispatchDraw ishlashga qanday ta'sir qiladi?

dispatchDraw har bir bolaviy View uchun draw() chaqiradi, umumiy vaqt bolalar soniga mutanosib. Hardware acceleration vaqtida dispatchDraw da Canvas operatsiyalarini qo'shish DisplayList-ni bekor qilishga va keshnii qayta qurishga olib kelishi mumkin. 5–10 bola uchun ta'sir minimal, 50+ bola uchun murakkab qatlamlarni keshlash tavsiya etiladi.

Nega dispatchDraw View uchun chaqirilmaydi?

View (ViewGroup emas) bolaviy elementlarga ega emas, shuning uchun dispatchDraw foydali ish bajarmaydi. Biroq, metod View sinfida polimorfizm uchun mavjud: draw() kodi har qanday View uchun dispatchDraw chaqiradi, lekin View amalga oshirilishida bolalarni chizish mantig'i yo'q. Faqat ViewGroup dispatchDraw-ni qayta belgilaydi.

dispatchDraw-da Canvas-ni o'zgartirish mumkinmi?

Ha, dispatchDraw Canvas qabul qiladi va super.dispatchDraw chaqirishdan oldin uni transformatsiya qilish mumkin (translate, rotate, scale). Bu barcha bolalar to'plamini yagona bir butun sifatida animatsiya qilish uchun qo'llaniladi. super.dispatchDraw tugagandan so'ng Canvas-ni dastlabki holatiga qaytarish tavsiya etiladi.

Xulosa

  • dispatchDraw(Canvas) — onDraw-dan so'ng barcha bolaviy View-larni rekursiv chizish uchun ViewGroup metodi
  • Draw konveyeri: drawBackground → onDraw → dispatchDraw → onDrawForeground
  • onDraw View-ning o'z mazmunini chizadi, dispatchDraw — bolaviy elementlarning mazmunini
  • setWillNotDraw(true) ViewGroup ni optimallashtiradi, onDraw-ni o'tkazib yuboradi, lekin dispatchDraw ishlashda davom etadi
  • dispatchDraw-ni qayta belgilash effektlarni qo'llash, Z-order ni o'zgartirish va bolalarning Canvas transformatsiyasi uchun ishlatiladi
  • super.dispatchDraw va maxsus chizish tartibi bolalar ustida nima bo'lishini belgilaydi
  • Oddiy View (ViewGroup emas) uchun dispatchDraw bo'sh — uning bolaviy elementlari yo'q

Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz

IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.

Loyihani muhokama qilish

Shuningdek o'qing