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), 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.
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ç |
|---|---|---|
| drawBackground | 1 | Arka plan çizimi (background drawable) |
| onDraw | 2 | View'in kendi içeriğini çizme |
| dispatchDraw | 3 | Tüm alt View'leri çizme (yalnızca ViewGroup) |
| onDrawForeground | 4 | Ön plan, kaydırma çubuğu ve dalga efekti çizimi |
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.
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.
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))
}
}
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.
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))
}
}
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
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.
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 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 (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.
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
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