onDraw() হল Android SDK এ View ক্লাসের একটি গুরুত্বপূর্ণ মেথড, যা একটি ভিউর বিষয়বস্তু অংকনের জন্য দায়িত্বপ্রাপ্ত। সিস্টেম onDraw কে View এর উপস্থিতির প্রতিটি আপডেটে কল করে — প্রাথমিক রেন্ডারিংয়ের সময়, invalidate() এর পরে বা আয়াম পরিবর্তনের সময়। Android Developers Documentation (2026) অনুসারে, Canvas API ব্যবহার করে onDraw ওভাররাইড করা Android অ্যাপ্লিকেশনে কস্টম গ্রাফিক্স তৈরির প্রাথমিক উপায়।
মূখ্য বিষয়সমূহ
onDraw(Canvas canvas) হল android.view.View ক্লাসের একটি protected মেথড, যা Android সিস্টেম ডাকে যখন একটি View আঁকার প্রয়োজন হয়। ডেভেলপার কস্টম অংকন বাস্তবায়নের জন্য এই মেথডটি ওভাররাইড করে: আকার, টেক্সট, ছবি, গ্রেডিয়েন্ট, অ্যানিমেশন। Canvas প্যারামিটার হল একটি গ্রাফিক্যাল পৃষ্ঠ যার উপর সকল অংকন কর্ম সম্পাদিত হয়।
মেথডের সিগনেচার সহজ: override fun onDraw(canvas: Canvas)। এই মেথডের মধ্যে, নতুন অবজেক্ট তৈরি করা উচিত নয় (GC বোঝা এড়াতে), দীর্ঘ কর্ম সম্পাদন করা উচিত নয় বা নেটওয়ার্কের সাথে কাজ করা উচিত নয়। View এর লাইফসাইকেলে onLayout (অবস্থান গণনা) এবং dispatchDraw (চাইল্ড উপাদান অংকন) এর মধ্যে onDraw মেথড অন্তর্ভুক্ত করে।
View থেকে ইনহেরিট করার সময়, যে কোনো বিষয়বস্তু প্রদর্শনের জন্য onDraw ওভাররাইড করা বাধ্যতামূলক — অন্যথা View খালি হবে। বিদ্যমান উপবর্গ (TextView, ImageView, Button) থেকে ইনহেরিট করার সময়, onDraw ওভাররাইড করা অলচ্ছিক এবং মানক বিষয়বস্তুর উপর অতিরিক্ত গ্রাফিক্স যোগ করার জন্য ব্যবহৃত হয়।
Android মূল থ্রেড (UI thread) থেকে ডাকা একটি কড়া সংজ্ঞায়িত ধারাবাহিকতায় View অংকন করে। সম্পূর্ণ চক্রটি তিনটি পর্যায় নিয়ে গঠিত: measure (মাত্রা পরিমাপ), layout (অবস্থান গণনা) এবং draw (রেন্ডারিং)। onDraw draw পর্যায়ের অংশ এবং View এর মাত্রা এবং অবস্থান নির্ধারিত হওয়ার পরে ডাকা হয়।
draw(Canvas canvas) হল View এর একটি পাবলিক মেথড যা onDraw এবং dispatchDraw কে ডাকে। draw মেথডটি ওভাররাইড করার জন্য ডিজাইন করা হয়নি — এর পরিবর্তে, onDraw ওভাররাইড করা হয়। বর্তমান View এর জন্য onDraw নিষ্পাদিত হওয়ার পর, dispatchDraw ডাকা হয়, যা সকল চাইল্ড View এর জন্য পুনরাবৃত্তিভাবে draw ডাকে (যদি বর্তমান View একটি ViewGroup কন্টেনার হয়)।
onDraw নিম্নলিখিত শর্তে ডাকা হয়: 1) View প্রথম বার দৃশ্য হয় (setVisibility(VISIBLE) এর পর); 2) অ্যাপ্লিকেশন এই View বা এর পেরেন্টে invalidate() ডাকে; 3) View এর আকার পরিবর্তন হয় (নতুন layout); 4) View এর সঙ্গে সম্পর্কিত একটি অ্যানিমেশন পরিবর্তন হয় (ValueAnimator বা ObjectAnimator এর মাধ্যমে); 5) View এর অবস্থা পরিবর্তন হয় (pressed, focused, enabled)।
Android 3.0 (API 11) থেকে, অধিকাংশ Canvas কর্ম GPU এর মাধ্যমে হার্ডওয়ার এক্সেলারেটেড হয়। ডেভেলপার canvas.isHardwareAccelerated() এর মাধ্যমে যাচাই করতে পারে যে এক্সেলারেশন সক্রিয় কি না। হার্ডওয়ার এক্সেলারেশনের সাথে, কিছু Canvas কর্ম সমর্থিত নয় (যেমন অ-আয়তাকার অঞ্চলের সাথে clipPath) এবং সেগুলো উপেক্ষিত বা ত্রুটি সৃষ্টি করতে পারে।
Canvas অংকন পদ্ধতির একটি সমৃদ্ধ সেট প্রদান করে। সকল পদ্ধতি বর্তমান সাহায্যক ব্যবস্থায় কাজ করে, যা রূপান্তর (translate, rotate, scale, skew) এর মাধ্যমে পরিবর্তন করা যেতে পারে। প্রতিটি পদ্ধতি একটি Paint অবজেক্ট স্বীকার করে যা রঙ, শৈলী, রেখার মোটাই, প্রভাব এবং অ্যান্টি-আলিয়াসিং সংজ্ঞায়িত করে।
| Canvas পদ্ধতি | উদ্দেশ্য | Paint এর মূখ্য প্যারামিটার |
|---|---|---|
| drawCircle | বৃত্ত আঁকা | centerX, centerY, radius, paint |
| drawRect | আয়তক্ষেত্র আঁকা | left, top, right, bottom, paint |
| drawLine | রেখা আঁকা | startX, startY, endX, endY, paint |
| drawPath | ইচ্ছামতো পথ আঁকা | path, paint |
| drawBitmap | বিটম্যাপ ছবি আঁকা | bitmap, srcRect, dstRect, paint |
| drawText | টেক্সট আঁকা | text, x, y, paint |
| drawArc | চাপ বা সেক্টর আঁকা | ovalRect, startAngle, sweepAngle, useCenter, paint |
| drawOval | ডিম্বাকার আঁকা | ovalRect, paint |
Paint অংকন শৈলী সংজ্ঞায়িত করে: রঙ (setColor), রেখার মোটাই (setStrokeWidth), ভরণের শৈলী (setStyle — FILL, STROKE, FILL_AND_STROKE), অ্যান্টি-আলিয়াসিং (setAntiAlias), প্রভাব (setShadowLayer, setMaskFilter) এবং গ্রেডিয়েন্ট (setShader)। View এর কনস্ট্রাক্টরে Paint এক বার তৈরি এবং কনফিগার করার পরামর্শ দেওয়া হয়, onDraw এর মধ্যে নয়, অংকন লূপে অবজেক্ট তৈরি এড়াতে।
Canvas একটি সাহায্যক ব্যবস্থা ব্যবহার করে যেখানে X-অক্ষ ডানে এবং Y-অক্ষ নিচের দিকে নির্দেশ করে। মূলবিন্দু (0, 0) হল View এর উপর বামের কোণ। draw পদ্ধতি ডাকার পূর্বে, ডেভেলপার canvas.translate(dx, dy), canvas.rotate(degrees, px, py), canvas.scale(sx, sy, px, py) এর মাধ্যমে সাহায্যক ব্যবস্থা পরিবর্তন করতে পারে। পরবর্তী সকল অংকন কর্ম রূপান্তরিত ব্যবস্থায় সম্পাদিত হবে।
onDraw মূল UI থ্রেডে কার্যকর করে, এবং এর মেয়াদ সরাসরি ফ্রেম হার (fps) কে প্রভাবিত করে। 60 fps বাজায় রাখতে, onDraw মেথডটি অবশ্যই 16 মিলিসেকেন্ডের মধ্যে সম্পাদিত হতে হবে। যে কোনো মন্থরতা ফ্রেম ড্রপ (jank) এর কারণ হয়, যা দৃশ্যত অ্যানিমেশন জটলতা বা স্ক্রল বিলম্ব হিসাবে দৃশ্যমান হয়।
মূখ্য নিয়ম onDraw অপ্টিমাইজেশনের জন্য: 1) onDraw এর মধ্যে অবজেক্ট তৈরি করবেন না — সকল Paint, Path, Rect অবজেক্ট ক্লাস ফিল্ড হওয়া উচিত; 2) মেমরি বরাদ্দ (new) করবেন না — এটি আবজর্জন কলেক্শন (GC) এবং ফ্রেম ড্রপের কারণ হয়; 3) জটিল কর্মগুলি কে Bitmap.createBitmap এর মাধ্যমে Bitmap এ ক্যাচ করুন এবং প্রস্তুত Bitmap আঁকুন; 4) I/O কর্ম বা রিসোর্স লোডিং করবেন না।
clipRect অংকন ক্ষেত্রকে একটি নির্দিষ্ট আয়তক্ষেত্রে সীমাবদ্ধ করে। এটি Canvas ক5্যা দৃশ্য ক্ষেত্রের বাইরে পিক্সেল আঁকার জন্য সময় নষ্ট করতে বাধা দিতে ব্যবহৃত হয়। এটি বিশেষ করে বড় তালিকা স্ক্রল করার সময় বা জুম করার সময় কার্যকর: clipRect দৃশ্য ক্ষেত্রে (dirty rect) সেট করুন, এবং Canvas শুধুমাত্র যা দৃশ্য তাই আঁকবে।
canvas.save() Canvas এর বর্তমান অবস্থা (রূপান্তর এবং clip) একটি স্ট্যাকে সংরক্ষণ করে। canvas.restore() শেষ সংরক্ষিত অবস্থা পুনরুদ্ধার করে। অস্থায়ী রূপান্তরের জন্য এটি প্রয়োজন: অবস্থা সংরক্ষণ করুন, translate/rotate প্রয়োগ করুন, আঁকুন, তারপর পুনরুদ্ধার করুন। save এবং restore হালকা এবং যুক্তিযুক্ত ব্যবহারে (10–15 নেস্টিং স্তরের চেয়ে কম) কর্মদক্ষতাকে প্রভাবিত করে না।
invalidate() হল View এর একটি মেথড যা সিস্টেমকে জানায় যে View এর বিষয়বস্তু পুরানো এবং পুনরায় আঁকার প্রয়োজন। invalidate কল করা একটি নতুন draw চক্র শুরু করে যাতে onDraw ডাকা হবে। invalidate কে শুধুমাত্র UI থ্রেড (মূল থ্রেড) থেকে ডাকা উচিত। পৃষ্ঠভূমি থ্রেড থেকে ডাকার জন্য postInvalidate ব্যবহৃত হয়।
postInvalidate() হল invalidate এর একটি থ্রেড-নিরাপদ সংস্করণ যা Handler এর মাধ্যমে মূল থ্রেডের ক্যুতে একটি পুনরাএংকন অনুরোধ প্রেরণ করে। এটি পৃষ্ঠভূমি কাজে ব্যবহৃত হয় যখন ডেটা লোডিং বা গণনা শেষ হওয়ার পর View আপডেট করার প্রয়োজন হয়। UI সিঙ্ক্রোনাইজেশনের জন্য এটিকে runOnUiThread এর সাথে যুক্ত করা যেতে পারে।
আংশিক পুনরাএংকন এর জন্য, invalidate(Rect dirty) বা invalidate(int l, int t, int r, int b) ব্যবহার করুন। এটি সিস্টেমকে জানায় যে শুধুমাত্র নির্দিষ্ট ক্ষেত্রটি পরিবর্তিত হয়েছে, সম্পূর্ণ View নয়। Android শুধুমাত্র dirty rect পুনরায় আঁকে অংকন অপ্টিমাইজ করে, যা আংশিক আপডেটের সাথে অ্যানিমেশনে কর্মদক্ষতা উল্লেখযোগ্যভাবে উন্নত করে।
আসুন Kotlin ব্যবহার করে Android এ কস্টম View তৈরিতে onDraw ওভাররাইড এর ব্যাবহারিক উদাহরণ দেখি।
এই উদাহরণটি একটি অ্যানিমেটেড ভরণের সাথে একটি বৃত্তাকার অগ্রগতি সূচক তৈরি করে। onDraw দুটি বৃত্ত আঁকে: একটি ধূসর পৃষ্ঠভূমি বৃত্ত এবং একটি রঙীন ভরণ বৃত্ত যার চাপ বর্তমান অগ্রগতি দ্বারা নির্ধারিত হয়। setProgress এ invalidate কল করা মান পরিবর্তনে পুনরাএংকন নিশ্চিত করে।
class CircularProgressView
@JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : View(context, attrs) {
private val bgPaint = Paint().apply {
style = Paint.Style.STROKE
strokeWidth = 12f
color = Color.parseColor("#E0E0E0")
isAntiAlias = true
}
private val progressPaint = Paint().apply {
style = Paint.Style.STROKE
strokeWidth = 12f
color = Color.BLUE
isAntiAlias = true
strokeCap = Paint.Cap.ROUND
}
var progress: Float = 0f
set(value) {
field = value.coerceIn(0f, 1f)
invalidate()
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val size = minOf(width, height) - 24f
val oval = RectF(12f, 12f,
12f + size, 12f + size)
canvas.drawArc(oval, 270f, 360f, false, bgPaint)
canvas.drawArc(oval, 270f,
progress * 360f,
false, progressPaint)
}
}
এই উদাহরণটি একটি গ্রেডিয়েন্ট সহ আয়তক্ষেত্র এবং এর উপর টেক্সট আঁকে। গ্রেডিয়েন্টটি LinearGradient (Shader) এর মাধ্যমে তৈরি করা হয়, এবং টেক্সট drawText এর মাধ্যমে। উভয় Paint অবজেক্ট কনস্ট্রাক্টরে এক বার তৈরি করা হয়, যখন onDraw শুধুমাত্র View এর বর্তমান প্রস্থের উপর ভিত্তিকে আয়তক্ষেত্রের আকার আপডেট করে।
class GradientTextView(context: Context)
: View(context) {
private val shaderPaint = Paint().apply {
isAntiAlias = true
}
private val textPaint = Paint().apply {
color = Color.WHITE
textSize = 48f
isAntiAlias = true
textAlign = Paint.Align.CENTER
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val gradient = LinearGradient(
0f, 0f, width.toFloat(), 0f,
Color.parseColor("#FF6B35"),
Color.parseColor("#FF0040"),
Shader.TileMode.CLAMP
)
shaderPaint.shader = gradient
canvas.drawRect(0f, 0f,
width.toFloat(),
height.toFloat(), shaderPaint)
val xCenter = width / 2f
val yCenter = height / 2f
val yOffset = (textPaint.descent() +
textPaint.ascent()) / 2f
canvas.drawText("Hello from Canvas",
xCenter, yCenter - yOffset,
textPaint)
}
}
এই উদাহরণটি একটি অ্যানিমেটেড ঘড়ি তৈরি করে যা প্রতি 1000 মিলিসেকেন্ডে অংকন আপডেট করে। onDraw এর মধ্যে postDelayed এক সেকেন্ড পর invalidate কল করে, একটি অসীম পুনরাএংকন লূপ তৈরি করে। ঘড়ির কাটাগুলি বিভিন্ন দৈর্ঘ্য এবং মোটাইর সাথে drawLine এর মাধ্যমে আঁকা হয়।
class AnalogClockView(context: Context)
: View(context) {
private val handPaint = Paint().apply {
style = Paint.Style.STROKE
isAntiAlias = true
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val cx = width / 2f
val cy = height / 2f
val radius = minOf(cx, cy) - 20f
val now = Calendar.getInstance()
val hours = now.get(Calendar.HOUR) % 12
val minutes = now.get(Calendar.MINUTE)
val seconds = now.get(Calendar.SECOND)
val secondAngle = Math.toRadians(
seconds * 6f - 90f)
handPaint.strokeWidth = 2f
handPaint.color = Color.RED
canvas.drawLine(cx, cy,
cx + cos(secondAngle) * radius * 0.8f,
cy + sin(secondAngle) * radius * 0.8f,
handPaint)
postDelayed({ invalidate() }, 1000)
}
}
প্রায়শই জিজ্ঞাসিত প্রশ্ন
না, onDraw কে সরাসরি ডাকা উচিত নয়। পুনরাএংকনের অনুরোধ করতে, invalidate() (UI থ্রেড থেকে) বা postInvalidate() (পৃষ্ঠভূমি থ্রেড থেকে) ব্যবহার করুন। সিস্টেম সিদ্ধান্ত করবে কথায় onDraw ডাকতে হবে এবং একাধিক invalidate কলকে একটি পাসে মিশিয়ে অংকন অপ্টিমাইজ করবে।
কারণ: View লুকানো আছে (setVisibility(GONE) বা INVISIBLE); View Window পদানুক্রমে যোগ করা হয়নি; View এর আকার 0 (প্রস্থ বা দৈর্ঘ্য = 0); setWillNotDraw(true) ডাকা হয় (ViewGroup এর জন্য ডিফল্ট true)। ডিবাগ করার সময় এগুলো প্রতিটি বিন্দু যাচাই করুন।
60 fps এ, onDraw প্রতি সেকেন্ড 60 বার পর্যন্ত ডাকা যেতে পারে। 120 fps এ (120 Hz ডিসপ্লে সহ ডিভাইসে) — 120 বার পর্যন্ত। প্রতিটি কল প্রায় 8–16 মিলিসেকেন্ডের মধ্যে সম্পাদিত হতে হবে। ObjectAnimator বা ValueAnimator এর মাধ্যমে সক্রিয় অ্যানিমেশনের সময়, ফ্রিকোয়েন্সি অ্যানিমেশন ফ্রেমের সংখ্যা দ্বারা নির্ধারিত হয়।
onDraw View এর নিজস্ব বিষয়বস্তু আঁকার জন্য দায়িত্বপ্রাপ্ত। dispatchDraw চাইল্ড View (ViewGroup এ) আঁকার জন্য দায়িত্বপ্রাপ্ত। dispatchDraw onDraw এর পরে ডাকা হয় এবং সকল চাইল্ড উপাদানের জন্য পুনরাবৃত্তিভাবে যায়। একটি সাধারণ View (কোনো ViewGroup নয়) এর জন্য, dispatchDraw খালি থাকে।
হ্যাঁ, Canvas কে Canvas(bitmap) এর মাধ্যমে Bitmap এর জন্য তৈরি করা যেতে পারে এবং যে কোনো থ্রেডে তাতে আঁকা যেতে পারে। এটি পৃষ্ঠভূমিতে জটিল গ্রাফিক্স প্রাক-রেন্ডার করার জন্য ব্যবহৃত হয়। তবে, onDraw এ পাঠানো Canvasটি সিস্টেমের এবং শুধুমাত্র onDraw মেথডের মধ্যে UI থ্রেডে ব্যবহার করা যেতে পারে।
সারাংশ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন