dispatchDraw() — ay isang paraan ng klase ng ViewGroup na responsable para sa recursive na pagguhit ng lahat ng child View sa hierarchy ng Android. Ayon sa Android Developers Documentation (2026), ang dispatchDraw ay awtomatikong tinatawag pagkatapos ng onDraw sa draw() na paraan ng pangunahing View at dumadaan sa lahat ng child element, na tinatawag ang kanilang sariling draw(). Ang mga developer ay nag-o-override ng dispatchDraw sa custom na ViewGroup para magdagdag ng mga epekto, magpatong ng graphics sa ibabaw ng mga bata, o baguhin ang pagkakasunod-sunod ng pagguhit.
Pangunahin
dispatchDraw(Canvas canvas) — ay isang protected na paraan ng klase ng ViewGroup na tinatawag ng Android system para sa pagguhit ng lahat ng child View ng kasalukuyang container. Ang dispatchDraw ay bahagi ng standard na pipeline ng draw: una ay isinasagawa ang onDraw (pagguhit ng nilalaman ng View mismo), pagkatapos ay ang dispatchDraw (recursive na pagguhit ng mga bata), pagkatapos ay ang onDrawForeground (pagguhit ng foreground at scrollbars). Ang paraan ay hindi para sa direktang pagtawag mula sa code ng application.
Ang standard na implementasyon ng dispatchDraw sa ViewGroup ay umiikot sa lahat ng child View, sinusuri ang kanilang visibility at tinatawag para sa bawat isa ang draw(Canvas). Ang pagkakasunod-sunod ng pagdaan ay tumutugma sa mga index ng mga bata (mula 0 hanggang childCount - 1). Kung ang mga child View ay nagkakapatong, ang mga huli sa listahan ay iginuguhit sa ibabaw ng mga nauna. Sa pamamagitan ng pagbabago ng pagkakasunod-sunod sa dispatchDraw, maaaring baguhin ang Z-order ng pagguhit.
Para sa View (hindi ViewGroup) ang dispatchDraw na paraan ay walang laman — ang ordinaryong View ay walang child element, kaya walang dapat iguhit. Ang paraan ay umiiral sa base class na View, ngunit tinatawag lamang para sa mga instance ng ViewGroup. Maaaring suriin ng developer kung ang View ay may child element sa pamamagitan ng default na pag-uugali ng dispatchDraw, ngunit kadalasan ay mas simple na suriin ang instanceof ViewGroup.
Ang paraan draw(Canvas) ng klase ng View ay nag-o-organisa ng tatlong-yugtong pipeline ng pagguhit. Unang yugto — pagtawag ng onDraw(canvas), kung saan iginuguhit ng View ang nilalaman nito. Ikalawang yugto — pagtawag ng dispatchDraw(canvas), na nagsisimula sa pagguhit ng mga child View. Ikatlong yugto — onDrawForeground(canvas), responsable para sa foreground layer, scrollbars at ripple effects. Ang pagkakasunod-sunod na ito ay ginagarantiyahan ang tamang pagkakapatong ng mga graphic layer.
onDraw ay palaging isinasagawa bago ang dispatchDraw. Ito ay nangangahulugan na ang nilalaman ng parent View ay ipinapakita sa ilalim ng mga child View. Kung kailangan gumuhit ng isang bagay sa ibabaw ng mga bata, ito ay ginagawa sa onDrawForeground o sa naka-override na dispatchDraw na may pagtawag ng super.dispatchDraw(canvas) at kasunod na pagguhit sa ibabaw. Ang background ay iginuguhit bago pa ang onDraw — sa drawBackground(canvas) sa loob ng paraan draw().
Sa hardware acceleration ang pipeline ng draw ay gumagana sa pamamagitan ng GPU. Ang View ay iginuguhit sa DisplayList — isang listahan ng mga utos ng pagguhit na ini-cache at ginagamit muli. Ang dispatchDraw sa hardware-accelerated mode ay nagdaragdag ng DisplayList ng mga child View sa pangkalahatang DisplayList ng eksena. Ang pagbabago ng dispatchDraw ay maaaring humantong sa invalidation ng DisplayList at muling pagbuo ng cache, na nakakaapekto sa pagganap.
| Paraan | Pagkakasunod-sunod ng tawag | Layunin |
|---|---|---|
| drawBackground | 1 | Pagguhit ng background (background drawable) |
| onDraw | 2 | Pagguhit ng nilalaman ng View mismo |
| dispatchDraw | 3 | Pagguhit ng lahat ng child View (para lamang sa ViewGroup) |
| onDrawForeground | 4 | Pagguhit ng foreground, scrollbar at ripple effect |
onDraw ay responsable para sa pagguhit ng nilalaman ng View mismo — mga hugis, teksto, larawan na pag-aari ng partikular na elementong ito. dispatchDraw ay responsable para sa pagguhit ng mga child View — lahat ng elemento na nasa loob ng ViewGroup. Kung ang ViewGroup ay hindi nag-o-override ng dispatchDraw, ang implementasyon mula sa ViewGroup ang ginagamit, na simpleng recursive na dumadaan sa childCount at tumatawag ng draw para sa bawat bata.
Para sa ViewGroup na hindi gumuhit ng sariling nilalaman (halimbawa, FrameLayout, LinearLayout), ang onDraw ay maaaring i-optimize sa pamamagitan ng pagtatakda ng setWillNotDraw(true). Sa kasong ito, ang onDraw ay hindi kailanman tinatawag, na nakakatipid ng mga resources. Ang dispatchDraw ay patuloy na gumagana at tumatawag ng draw para sa mga child element. Lahat ng standard na ViewGroup (LinearLayout, RelativeLayout, ConstraintLayout) ay gumagamit ng setWillNotDraw(true).
Kung ang dispatchDraw ay na-override nang hindi tinatawag ang super.dispatchDraw(canvas), ang mga child View ay hindi iguguhit. Ito ay maaaring maging kapaki-pakinabang para sa pansamantalang pagtatago ng lahat ng bata, ngunit sa karamihan ng mga kaso ay nagdudulot ng mga error. Inirerekomendang praktika: tawagan ang super.dispatchDraw(canvas) sa simula ng na-override na paraan, pagkatapos ay idagdag ang iyong sariling graphics (halimbawa, overlay na may alpha channel) sa ibabaw ng mga bata.
Gumawa tayo ng OverlayViewGroup — isang custom na ViewGroup na nagdaragdag ng semi-transparent na layer na may text label sa ibabaw ng lahat ng child View. Ang dispatchDraw ay unang tumatawag ng super (pagguhit ng lahat ng bata), pagkatapos ay gumuhit ng overlay rectangle at text. Ang Paint ay ginagawa sa constructor upang maiwasan ang mga alokasyon sa draw loop.
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("PREVIEW MODE",
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))
}
}
Ang sumusunod na halimbawa ay nagpapakita ng pagbabago ng pagkakasunod-sunod ng pagguhit ng mga child element. Ang CircularRevealLayout ay nag-o-override ng dispatchDraw at gumuhit ng mga bata sa reverse na pagkakasunod-sunod, na lumilikha ng epekto ng baligtad na Z-order. Para sa animasyon, isang cyclic na paglipat ng index ng pagguhit ay idinagdag batay sa animated na halaga ng offset.
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 ay ginagamit sa mga sitwasyon kung saan kailangan mong impluwensyahan ang proseso ng pagguhit ng mga child View nang hindi naaapektuhan ang sariling nilalaman ng ViewGroup. Pangunahing sitwasyon: paglalapat ng isang karaniwang epekto (overlay, shadow, gradient) sa ibabaw ng lahat ng bata; pagbabago ng pagkakasunod-sunod ng Z-order para sa paglikha ng epekto ng lalim; pag-animate ng paglitaw o pagkawala ng mga child element sa pamamagitan ng Canvas transformations.
Kung kinakailangan ang pagpapatong ng graphics sa ilalim ng mga child element (epekto ng background), gamitin ang onDraw — ang dispatchDraw ay tinatawag pagkatapos nito. Kung ang graphics ay dapat nasa ibabaw ng mga bata — gamitin ang dispatchDraw na may tawag na super, pagkatapos ay Canvas.draw. Kung kinakailangan ang pandaigdigang pagbabago ng kulay o transparency, mas maginhawang gamitin ang canvas.saveLayerAlpha() sa dispatchDraw, na bumabalot sa pagguhit ng mga bata.
Hindi inirerekomenda ang paggamit ng dispatchDraw para sa: 1) pagguhit ng kumplikadong animasyon sa real-time (gamitin ang invalidate at onDraw); 2) paggawa ng mga screenshot ng ViewGroup (gamitin ang buildDrawingCache() o View.draw(Canvas)); 3) pagbabago ng mga child View (coordinates, sizes — ito ay gawain ng onLayout, hindi ng dispatchDraw). dispatchDraw — para lamang sa paglalapat ng mga visual effect.
Mga Madalas Itanong
Hindi, ang dispatchDraw — protected na paraan na tinatawag ng Android system sa loob ng public na paraan draw(). Ang direktang pagtawag ng dispatchDraw ay walang saysay, dahil hindi ito nagsasagawa ng mga paghahandang aksyon (pag-save ng Canvas, pagguhit ng background at foreground). Sa halip, gamitin ang View.draw(Canvas) para sa programmatic na pagguhit sa anumang Canvas.
Kung tatawagin mo ang super.dispatchDraw(canvas) pagkatapos ng iyong sariling mga operasyon sa pagguhit, ang mga child View ay iguguhit sa ibabaw ng custom na graphics. Binabago nito ang pagkakapatong ng layer: unang iginuguhit ang custom na layer, pagkatapos ang mga bata. Kung kinakailangan ang kabaligtaran na sitwasyon (graphics sa ibabaw ng mga bata), tawagan muna ang super.dispatchDraw, pagkatapos ang iyong sariling mga operasyon.
dispatchDraw ay tumatawag ng draw() para sa bawat child View, ang kabuuang oras ay proporsyonal sa bilang ng mga bata. Sa hardware acceleration, ang pagdaragdag ng mga Canvas operation sa dispatchDraw ay maaaring humantong sa invalidation ng DisplayList at muling pagbuo ng cache. Para sa 5–10 bata ang epekto ay minimal, para sa 50+ bata inirerekomenda ang pag-cache ng mga kumplikadong overlay.
View (hindi ViewGroup) ay walang child element, kaya ang dispatchDraw ay hindi gumagawa ng kapaki-pakinabang na trabaho. Gayunpaman, ang paraan ay umiiral sa base class na View para sa polymorphism: ang code sa draw() ay tumatawag ng dispatchDraw para sa anumang View, ngunit ang implementasyon ng View ay hindi naglalaman ng lohika ng pagguhit ng mga bata. Tanging ang ViewGroup ang nag-o-override ng dispatchDraw.
Oo, ang dispatchDraw ay tumatanggap ng Canvas at maaaring i-transform bago tawagan ang super.dispatchDraw (translate, rotate, scale). Ito ay inilalapat para sa pag-animate ng buong set ng mga bata bilang isang solong kabuuan. Pagkatapos makumpleto ang super.dispatchDraw, inirerekomenda na ibalik ang Canvas sa orihinal na estado.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din