dispatchDraw() হল ViewGroup ক্লাসের একটি মেথড যা Android হায়ারার্কিতে সমস্ত চাইল্ড View-এর রিকার্সিভ অঙ্কনের জন্য দায়ী। Android Developers Documentation (2026) অনুসারে, প্রধান View-এর draw() মেথডে onDraw-এর পরে dispatchDraw স্বয়ংক্রিয়ভাবে কল হয় এবং সমস্ত চাইল্ড এলিমেন্টের মধ্য দিয়ে যায়, তাদের নিজস্ব draw() কল করে। ডেভেলপাররা কাস্টম ViewGroup-এ ইফেক্ট যোগ করতে, চাইল্ডদের উপরে গ্রাফিক্স ওভারলে করতে বা অঙ্কনের ক্রম পরিবর্তন করতে dispatchDraw ওভাররাইড করে।
মূল বিষয়
dispatchDraw(Canvas canvas) হল ViewGroup ক্লাসের একটি protected মেথড যা Android সিস্টেম বর্তমান কন্টেইনারের সমস্ত চাইল্ড View অঙ্কনের জন্য কল করে। dispatchDraw স্ট্যান্ডার্ড ড্র পাইপলাইনের অংশ: প্রথমে onDraw এক্সিকিউট হয় (View-এর নিজস্ব বিষয়বস্তু অঙ্কন), তারপর dispatchDraw (চাইল্ডদের রিকার্সিভ অঙ্কন), তারপর onDrawForeground (ফোরগ্রাউন্ড এবং স্ক্রলবার অঙ্কন)। মেথডটি অ্যাপ্লিকেশন কোড থেকে সরাসরি কল করার জন্য নয়।
ViewGroup-এ dispatchDraw-এর স্ট্যান্ডার্ড ইমপ্লিমেন্টেশন সমস্ত চাইল্ড View-এর মধ্য দিয়ে যায়, তাদের দৃশ্যমানতা পরীক্ষা করে এবং প্রতিটির জন্য draw(Canvas) কল করে। ট্রাভার্সাল ক্রম চাইল্ড ইনডেক্স (0 থেকে childCount - 1 পর্যন্ত) অনুসারে হয়। যদি চাইল্ড View ওভারল্যাপ করে, তালিকায় পরেরগুলি আগেরগুলির উপরে অঙ্কিত হয়। dispatchDraw-এ ক্রম পরিবর্তন করে অঙ্কনের Z-order পরিবর্তন করা যায়।
View-এর জন্য (ViewGroup নয়), dispatchDraw মেথড খালি — একটি সাধারণ View-এর কোনো চাইল্ড এলিমেন্ট নেই, তাই অঙ্কনের মতো কিছু নেই। মেথডটি বেস View ক্লাসে বিদ্যমান কিন্তু শুধুমাত্র ViewGroup ইন্সট্যান্সে কল করা হয়। একজন ডেভেলপার dispatchDraw-এর ডিফল্ট আচরণের মাধ্যমে পরীক্ষা করতে পারেন যে একটি View-এ চাইল্ড এলিমেন্ট আছে কিনা, তবে প্রায়শই instanceof ViewGroup পরীক্ষা করা সহজ।
View ক্লাসের draw(Canvas) মেথড একটি তিন-স্তরের অঙ্কন পাইপলাইন সংগঠিত করে। প্রথম স্তর হল onDraw(canvas) কল করা, যেখানে View তার নিজস্ব বিষয়বস্তু অঙ্কন করে। দ্বিতীয় স্তর হল dispatchDraw(canvas) কল করা, যা চাইল্ড View-এর অঙ্কন শুরু করে। তৃতীয় স্তর হল onDrawForeground(canvas), যা ফোরগ্রাউন্ড লেয়ার, স্ক্রলবার এবং রিপল ইফেক্টের জন্য দায়ী। এই ক্রম গ্রাফিক্যাল লেয়ারের সঠিক ওভারলে ক্রম নিশ্চিত করে।
onDraw সর্বদা dispatchDraw-এর আগে এক্সিকিউট হয়। এর অর্থ হল প্যারেন্ট View-এর বিষয়বস্তু চাইল্ড View-এর নীচে প্রদর্শিত হয়। যদি আপনার চাইল্ডদের উপরে কিছু অঙ্কন করতে হয়, তা onDrawForeground-এ বা ওভাররাইড করা dispatchDraw-এ super.dispatchDraw(canvas) কল করে এবং তারপর উপরে অঙ্কন করে করা হয়। ব্যাকগ্রাউন্ড onDraw-এর আগেও draw() মেথডের ভিতরে drawBackground(canvas)-এ অঙ্কিত হয়।
হার্ডওয়্যার এক্সিলারেশন-এর সাথে, ড্র পাইপলাইন GPU-র মাধ্যমে কাজ করে। View একটি DisplayList-এ অঙ্কিত হয় — অঙ্কন কমান্ডের একটি তালিকা যা ক্যাশে এবং পুনরায় ব্যবহার করা হয়। হার্ডওয়্যার-এক্সিলারেটেড মোডে dispatchDraw চাইল্ড View-এর DisplayList-গুলিকে দৃশ্যের সামগ্রিক DisplayList-এ যোগ করে। dispatchDraw পরিবর্তন করলে DisplayList অবৈধ হতে পারে এবং ক্যাশে পুনর্নির্মাণ হতে পারে, যা কর্মক্ষমতা প্রভাবিত করে।
| মেথড | কল ক্রম | উদ্দেশ্য |
|---|---|---|
| drawBackground | 1 | ব্যাকগ্রাউন্ড অঙ্কন (background drawable) |
| onDraw | 2 | View-এর নিজস্ব বিষয়বস্তু অঙ্কন |
| dispatchDraw | 3 | সমস্ত চাইল্ড View অঙ্কন (শুধুমাত্র ViewGroup) |
| onDrawForeground | 4 | ফোরগ্রাউন্ড, স্ক্রলবার এবং রিপল ইফেক্ট অঙ্কন |
onDraw View-এর নিজস্ব বিষয়বস্তু — আকার, টেক্সট, ইমেজ যা এই নির্দিষ্ট এলিমেন্টের অন্তর্গত — অঙ্কনের জন্য দায়ী। dispatchDraw চাইল্ড View — ViewGroup-এর ভিতরে থাকা সমস্ত এলিমেন্ট — অঙ্কনের জন্য দায়ী। যদি একটি ViewGroup dispatchDraw ওভাররাইড না করে, ViewGroup থেকে ইমপ্লিমেন্টেশন ব্যবহার করা হয়, যা কেবল childCount-এর উপর রিকার্সিভভাবে যায় এবং প্রতিটি চাইল্ডের জন্য draw কল করে।
সেই ViewGroups-এর জন্য যারা নিজস্ব বিষয়বস্তু অঙ্কন করে না (যেমন FrameLayout, LinearLayout), setWillNotDraw(true) সেট করে onDraw অপ্টিমাইজ করা যেতে পারে। এই ক্ষেত্রে, onDraw কখনও কল হয় না, যা সম্পদ সাশ্রয় করে। dispatchDraw কাজ চালিয়ে যায় এবং চাইল্ড এলিমেন্টের জন্য draw কল করে। সমস্ত স্ট্যান্ডার্ড ViewGroup (LinearLayout, RelativeLayout, ConstraintLayout) setWillNotDraw(true) ব্যবহার করে।
যদি আপনি super.dispatchDraw(canvas) কল না করে dispatchDraw ওভাররাইড করেন, চাইল্ড View অঙ্কিত হবে না। এটি সাময়িকভাবে সমস্ত চাইল্ড লুকানোর জন্য উপযোগী হতে পারে, তবে বেশিরভাগ ক্ষেত্রে এটি ত্রুটি সৃষ্টি করে। প্রস্তাবিত অনুশীলন: ওভাররাইড করা মেথডের শুরুতে super.dispatchDraw(canvas) কল করুন, তারপর চাইল্ডদের উপরে আপনার নিজস্ব গ্রাফিক্স (যেমন আলফা চ্যানেল সহ ওভারলে) যোগ করুন।
চলুন OverlayViewGroup তৈরি করি — একটি কাস্টম ViewGroup যা সমস্ত চাইল্ড View-এর উপরে টেক্সট লেবেল সহ একটি আধা-স্বচ্ছ স্তর যোগ করে। dispatchDraw প্রথমে super কল করে (সমস্ত চাইল্ড অঙ্কন), তারপর ওভারলে আয়তক্ষেত্র এবং টেক্সট অঙ্কন করে। Paint কনস্ট্রাক্টরে তৈরি করা হয় যাতে ড্র লুপে অ্যালোকেশন এড়ানো যায়।
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("প্রিভিউ মোড",
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))
}
}
নিম্নলিখিত উদাহরণটি চাইল্ড এলিমেন্ট অঙ্কনের ক্রম পরিবর্তন প্রদর্শন করে। CircularRevealLayout dispatchDraw ওভাররাইড করে এবং চাইল্ডদের বিপরীত ক্রমে অঙ্কন করে, একটি উল্টানো Z-order প্রভাব তৈরি করে। অ্যানিমেশনের জন্য, অ্যানিমেটেড 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 সেই পরিস্থিতিতে ব্যবহার করা হয় যেখানে ViewGroup-এর নিজস্ব বিষয়বস্তুকে প্রভাবিত না করে চাইল্ড View-এর অঙ্কন প্রক্রিয়াকে প্রভাবিত করার প্রয়োজন হয়। প্রধান পরিস্থিতি: সমস্ত চাইল্ডের উপরে একটি সাধারণ ইফেক্ট (ওভারলে, শ্যাডো, গ্রেডিয়েন্ট) প্রয়োগ করা; গভীরতা প্রভাব তৈরি করতে Z-order পরিবর্তন করা; Canvas ট্রান্সফর্মেশনের মাধ্যমে চাইল্ড এলিমেন্টের আবির্ভাব বা অদৃশ্য হওয়া অ্যানিমেট করা।
যদি আপনার চাইল্ড এলিমেন্টের নীচে গ্রাফিক্স প্রয়োগ করার প্রয়োজন হয় (ব্যাকগ্রাউন্ড ইফেক্ট), onDraw ব্যবহার করুন — dispatchDraw তার পরে কল হয়। যদি গ্রাফিক্স চাইল্ডদের উপরে হওয়া উচিত — প্রথমে super কল করে, তারপর Canvas.draw ব্যবহার করে dispatchDraw ব্যবহার করুন। যদি আপনার বৈশ্বিক রঙ বা স্বচ্ছতা পরিবর্তনের প্রয়োজন হয়, তাহলে dispatchDraw-এ চাইল্ডদের অঙ্কন মোড়ানোর জন্য canvas.saveLayerAlpha() ব্যবহার করা সুবিধাজনক।
সুপারিশ করা হয় না dispatchDraw ব্যবহার করতে: 1) রিয়েল-টাইমে জটিল অ্যানিমেশন অঙ্কনের জন্য (invalidate এবং onDraw ব্যবহার করুন); 2) ViewGroup-এর স্ক্রিনশট তৈরির জন্য (buildDrawingCache() বা View.draw(Canvas) ব্যবহার করুন); 3) চাইল্ড View পরিবর্তনের জন্য (স্থানাঙ্ক, আকার — এগুলি onLayout-এর কাজ, dispatchDraw-এর নয়)। dispatchDraw শুধুমাত্র ভিজ্যুয়াল ইফেক্ট প্রয়োগের জন্য।
প্রায়শই জিজ্ঞাসিত প্রশ্ন
না, dispatchDraw একটি protected মেথড যা Android সিস্টেম পাবলিক draw() মেথডের ভিতরে কল করে। dispatchDraw-এর সরাসরি কল অর্থহীন কারণ এটি প্রস্তুতিমূলক কাজ (Canvas সংরক্ষণ, ব্যাকগ্রাউন্ড এবং ফোরগ্রাউন্ড অঙ্কন) করে না। পরিবর্তে, প্রোগ্রামেটিকভাবে যেকোনো Canvas-এ অঙ্কনের জন্য View.draw(Canvas) ব্যবহার করুন।
যদি আপনি আপনার নিজস্ব অঙ্কন অপারেশনের পরে super.dispatchDraw(canvas) কল করেন, চাইল্ড View কাস্টম গ্রাফিক্সের উপরে অঙ্কিত হবে। এটি লেয়ার ক্রম পরিবর্তন করে: প্রথমে কাস্টম লেয়ার অঙ্কিত হয়, তারপর চাইল্ডরা। যদি আপনার বিপরীত পরিস্থিতির প্রয়োজন হয় (চাইল্ডদের উপরে গ্রাফিক্স), প্রথমে super.dispatchDraw কল করুন, তারপর আপনার নিজস্ব অপারেশন।
dispatchDraw প্রতিটি চাইল্ড View-এর জন্য draw() কল করে, এবং মোট সময় চাইল্ডের সংখ্যার অনুপাতে হয়। হার্ডওয়্যার এক্সিলারেশনের সাথে, dispatchDraw-এ Canvas অপারেশন যোগ করলে DisplayList অবৈধ হতে পারে এবং ক্যাশে পুনর্নির্মাণ হতে পারে। 5–10 চাইল্ডের জন্য প্রভাব ন্যূনতম, 50+ চাইল্ডের জন্য জটিল ওভারলে ক্যাশে করার সুপারিশ করা হয়।
একটি View (ViewGroup নয়) -এ কোনো চাইল্ড এলিমেন্ট নেই, তাই dispatchDraw কোনো উপযোগী কাজ করে না। তবে, পলিমরফিজমের জন্য বেস View ক্লাসে মেথডটি বিদ্যমান: draw()-এ কোড যেকোনো View-এর জন্য dispatchDraw কল করে, কিন্তু View-এর ইমপ্লিমেন্টেশনে চাইল্ড অঙ্কনের লজিক নেই। শুধুমাত্র ViewGroup dispatchDraw ওভাররাইড করে।
হ্যাঁ, dispatchDraw একটি Canvas গ্রহণ করে এবং super.dispatchDraw কল করার আগে এটি ট্রান্সফর্ম করা যেতে পারে (translate, rotate, scale)। এটি চাইল্ডদের পুরো সেটকে একটি ইউনিট হিসাবে অ্যানিমেট করতে ব্যবহৃত হয়। super.dispatchDraw সম্পূর্ণ হওয়ার পরে, Canvas-কে তার মূল অবস্থায় পুনরুদ্ধার করার সুপারিশ করা হয়।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন