dispatchDraw(): nedir, çağrı mekanizması ve onDraw'dan farkı

Yazar: IT Sectr Yayınlanma: 2026-07-22 Okuma süresi: 9 dk

dispatchDraw(), Android hiyerarşisindeki tüm alt View'lerin yinelemeli çiziminden sorumlu olan ViewGroup sınıfının bir yöntemidir. Android Developers Documentation (2026)'ya göre dispatchDraw, ana View'in draw() yönteminde onDraw'dan sonra otomatik olarak çağrılır ve tüm alt öğeleri dolaşarak kendi draw()'larını çağırır. Geliştiriciler, özel ViewGroup'larda dispatchDraw'ı geçersiz kılarak efekt eklemek, alt öğelerin üzerine grafik yerleştirmek veya çizim sırasını değiştirmek için kullanır.

Önemli Noktalar

  • dispatchDraw(Canvas canvas), alt View'leri çizmek için onDraw'dan sonra çağrılan ViewGroup'un protected yöntemidir
  • draw(Canvas canvas), sırasıyla onDraw, dispatchDraw ve onDrawForeground'u çağıran View'in public final yöntemidir
  • onDraw View'in kendi içeriğini çizerken, dispatchDraw tüm alt öğeleri çizer
  • setWillNotDraw(true), kendi içeriğini çizmeyen, yalnızca alt öğeleri çizen ViewGroup'lar için bir optimizasyondur
  • dispatchDraw'ı geçersiz kılma, efektler (blur, overlay) uygulamak veya alt öğe çizimini canlandırmak için kullanılır

dispatchDraw() nedir?

dispatchDraw(Canvas canvas), Android sisteminin mevcut kapsayıcının tüm alt View'lerini çizmek için çağırdığı ViewGroup sınıfının protected bir yöntemidir. dispatchDraw standart çizim hattının bir parçasıdır: önce onDraw yürütülür (View'in kendi içeriğini çizme), ardından dispatchDraw (alt öğelerin yinelemeli çizimi), ardından onDrawForeground (ön plan ve kaydırma çubuklarını çizme). Yöntem, uygulama kodundan doğrudan çağrılmak üzere tasarlanmamıştır.

ViewGroup'daki standart dispatchDraw uygulaması, tüm alt View'leri dolaşır, görünürlüklerini kontrol eder ve her biri için draw(Canvas) çağırır. Dolaşım sırası, alt öğe indekslerine (0'dan childCount - 1'e kadar) karşılık gelir. Alt View'ler örtüşüyorsa, listede sonraki olanlar öncekilerin üzerine çizilir. dispatchDraw'da sırayı değiştirmek, çizimin Z-sırasını değiştirmeye olanak tanır.

Bir View (ViewGroup değil) için dispatchDraw yöntemi boştur — normal bir View'ın alt öğesi yoktur, bu nedenle çizilecek bir şey yoktur. Yöntem temel View sınıfında bulunur ancak yalnızca ViewGroup örneklerinde çağrılır. Bir geliştirici, dispatchDraw'ın varsayılan davranışı aracılığıyla bir View'ın alt öğeleri olup olmadığını kontrol edebilir, ancak genellikle instanceof ViewGroup kontrolü daha basittir.

Çizim hattı: onDraw, dispatchDraw, onDrawForeground

View sınıfının draw(Canvas) yöntemi, üç aşamalı bir çizim hattı düzenler. İlk aşama, View'ın kendi içeriğini çizdiği onDraw(canvas) çağrısıdır. İkinci aşama, alt View'lerin çizimini tetikleyen dispatchDraw(canvas) çağrısıdır. Üçüncü aşama, ön plan katmanı, kaydırma çubukları ve dalga efekti için sorumlu olan onDrawForeground(canvas)'tır. Bu sıra, grafik katmanlarının doğru üst üste binme sırasını garanti eder.

onDraw her zaman dispatchDraw'dan önce yürütülür. Bu, üst View'in içeriğinin alt View'lerin altında görüntülendiği anlamına gelir. Alt öğelerin üzerine bir şey çizmeniz gerekiyorsa, bu onDrawForeground'da veya geçersiz kılınmış bir dispatchDraw'da super.dispatchDraw(canvas) çağrılarak ve ardından üzerine çizilerek yapılır. Arka plan, onDraw'dan önce bile draw() yöntemi içindeki drawBackground(canvas)'ta çizilir.

Donanım hızlandırma ile çizim hattı GPU üzerinden çalışır. View, bir DisplayList'e (önbelleğe alınan ve yeniden kullanılan bir çizim komutları listesi) çizilir. Donanım hızlandırmalı modda dispatchDraw, alt View'lerin DisplayList'lerini sahnenin genel DisplayList'ine ekler. dispatchDraw'ı değiştirmek, DisplayList'i geçersiz kılabilir ve önbellek yeniden oluşturmasına neden olarak performansı etkileyebilir.

YöntemÇağrı sırasıAmaç
drawBackground1Arka plan çizimi (background drawable)
onDraw2View'in kendi içeriğini çizme
dispatchDraw3Tüm alt View'leri çizme (yalnızca ViewGroup)
onDrawForeground4Ön plan, kaydırma çubuğu ve dalga efekti çizimi

dispatchDraw ve onDraw arasındaki fark

onDraw, View'in kendi içeriğini (bu belirli öğeye ait şekiller, metin, resimler) çizmekten sorumludur. dispatchDraw, alt View'leri (ViewGroup içinde bulunan tüm öğeler) çizmekten sorumludur. Bir ViewGroup dispatchDraw'ı geçersiz kılmazsa, ViewGroup'daki uygulama kullanılır ve bu da childCount'u yinelemeli olarak dolaşarak her alt öğe için draw'ı çağırır.

Kendi içeriğini çizmeyen bir ViewGroup (örneğin, FrameLayout, LinearLayout) için onDraw, setWillNotDraw(true) ayarlanarak optimize edilebilir. Bu durumda onDraw asla çağrılmaz, bu da kaynak tasarrufu sağlar. dispatchDraw çalışmaya devam eder ve alt öğeler için draw'ı çağırır. Tüm standart ViewGroup'lar (LinearLayout, RelativeLayout, ConstraintLayout) setWillNotDraw(true) kullanır.

super.dispatchDraw(canvas) çağırmadan dispatchDraw'ı geçersiz kılarsanız, alt View'ler çizilmez. Bu, tüm alt öğeleri geçici olarak gizlemek için yararlı olabilir, ancak çoğu durumda hatalara neden olur. Önerilen uygulama: geçersiz kılınan yöntemin başında super.dispatchDraw(canvas) çağırın, ardından alt öğelerin üzerine kendi grafiklerinizi (örneğin, alfa kanallı bir kaplama) ekleyin.

Kotlin'de dispatchDraw geçersiz kılma örneği

OverlayViewGroup oluşturalım — tüm alt View'lerin üzerine metin etiketli yarı saydam bir katman ekleyen özel bir ViewGroup. dispatchDraw önce super'i çağırır (tüm alt öğeleri çizer), ardından kaplama dikdörtgenini ve metni çizer. Paint, çizim döngüsünde bellek ayırmalarını önlemek için kurucuda oluşturulur.

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("ÖNİZLEME MODU",
            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 ile canlandırılmış Z-sırası

Aşağıdaki örnek, alt öğelerin çizim sırasını değiştirmeyi gösterir. CircularRevealLayout, dispatchDraw'ı geçersiz kılar ve alt öğeleri ters sırada çizerek tersine çevrilmiş bir Z-sırası efekti oluşturur. Canlandırma için, canlandırılmış offset değerine dayalı olarak çizim indeksinin döngüsel bir kaydırması eklenir.

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'de dispatchDraw ne zaman kullanılır

dispatchDraw, ViewGroup'un kendi içeriğini etkilemeden alt View'lerin çizim sürecini etkilemeniz gereken senaryolarda kullanılır. Ana senaryolar: tüm alt öğelerin üzerine ortak bir efekt (kaplama, gölge, gradyan) uygulamak; derinlik efektleri oluşturmak için Z-sırasını değiştirmek; Canvas dönüşümleri aracılığıyla alt öğelerin görünmesini veya kaybolmasını canlandırmak.

Alt öğelerin altına grafik uygulamanız gerekiyorsa (arka plan efekti), onDraw kullanın — dispatchDraw ondan sonra çağrılır. Grafikler alt öğelerin üzerinde olmalıysa — önce super'i çağırarak, ardından Canvas.draw kullanarak dispatchDraw kullanın. Küresel bir renk veya şeffaflık değişikliği gerekiyorsa, alt öğelerin çizimini sarmak için dispatchDraw'da canvas.saveLayerAlpha() kullanmak uygundur.

Önerilmez dispatchDraw kullanmak: 1) gerçek zamanlı karmaşık canlandırma çizmek için (invalidate ve onDraw kullanın); 2) bir ViewGroup'un ekran görüntüsünü oluşturmak için (buildDrawingCache() veya View.draw(Canvas) kullanın); 3) alt View'leri değiştirmek için (koordinatlar, boyutlar — bunlar onLayout'un görevleridir, dispatchDraw'ın değil). dispatchDraw yalnızca görsel efektler uygulamak içindir.

Sıkça Sorulan Sorular

dispatchDraw doğrudan sistem olmadan çağrılabilir mi?

Hayır, dispatchDraw, Android sistemi tarafından genel draw() yöntemi içinde çağrılan protected bir yöntemdir. dispatchDraw'ı doğrudan çağırmanın bir anlamı yoktur çünkü hazırlık eylemleri (Canvas'ı kaydetme, arka plan ve ön plan çizme) gerçekleştirmez. Bunun yerine, programlı olarak rastgele bir Canvas'a çizim yapmak için View.draw(Canvas) kullanın.

Özel çizimden sonra super.dispatchDraw çağrıldığında ne olur?

Kendi çizim işlemlerinizden sonra super.dispatchDraw(canvas) çağırırsanız, alt View'ler özel grafiklerin üzerine çizilir. Bu, katman sırasını değiştirir: önce özel katman çizilir, ardından alt öğeler. Ters duruma (alt öğelerin üzerinde grafik) ihtiyacınız varsa, önce super.dispatchDraw'ı, ardından kendi işlemlerinizi çağırın.

dispatchDraw performansı nasıl etkiler?

dispatchDraw her alt View için draw() çağırır ve toplam süre alt öğe sayısıyla orantılıdır. Donanım hızlandırmada, dispatchDraw'a Canvas işlemleri eklemek DisplayList'i geçersiz kılabilir ve önbellek yeniden oluşturmasına neden olabilir. 5–10 alt öğe için etki minimumdur, 50+ alt öğe için karmaşık kaplamaları önbelleğe almak önerilir.

Bir View için dispatchDraw neden çağrılmaz?

Bir View (ViewGroup değil) alt öğelere sahip değildir, bu nedenle dispatchDraw yararlı bir iş yapmaz. Ancak, yöntem çok biçimlilik için temel View sınıfında bulunur: draw() içindeki kod herhangi bir View için dispatchDraw'ı çağırır, ancak View uygulaması alt öğe çizim mantığı içermez. dispatchDraw'ı yalnızca ViewGroup geçersiz kılar.

dispatchDraw'da Canvas değiştirilebilir mi?

Evet, dispatchDraw bir Canvas kabul eder ve super.dispatchDraw çağrılmadan önce dönüştürülebilir (translate, rotate, scale). Bu, tüm alt öğe kümesini tek bir birim olarak canlandırmak için kullanılır. super.dispatchDraw tamamlandıktan sonra Canvas'ın orijinal durumuna geri yüklenmesi önerilir.

Özet

  • dispatchDraw(Canvas), onDraw'dan sonra tüm alt View'leri yinelemeli olarak çizen ViewGroup yöntemidir
  • Çizim hattı: drawBackground → onDraw → dispatchDraw → onDrawForeground
  • onDraw View'in kendi içeriğini çizer, dispatchDraw alt öğelerin içeriğini çizer
  • setWillNotDraw(true), onDraw'ı atlayarak ViewGroup'u optimize eder, ancak dispatchDraw çalışmaya devam eder
  • dispatchDraw'ı geçersiz kılma, efekt uygulamak, Z-sırasını değiştirmek ve alt öğelerin Canvas dönüşümleri için kullanılır
  • super.dispatchDraw ve özel çizimin sırası, alt öğelerin üzerinde ne görüneceğini belirler
  • Normal bir View (ViewGroup değil) için dispatchDraw boştur — alt öğesi yoktur

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.

Projeyi tartış

Ayrıca okuyun