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 View کی ڈرائنگ ایک سختی سے متعین ترتیب میں سرانسانے انجام دیتا ہے جب اسے اهم ثیرڈ (UI ثیرڈ) سے بلایا جاتا ہے۔ مکمل سائیکل تین مراحل پر مشتمل ہے: 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)۔ Paint کو onDraw کے اندر نہیں، بلکہ View کنسٹرکٹر میں ایک بار بنانے اور ترتیب دےنے کی سفارش کی جاتی ہے، تاکہ ڈرائنگ لوپ میں آبجیکٹ بنانے سے بچا جا سکے۔
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 کو نظر آنے والے علاقے کے باہر پیکسل کھینچنے میں وقت ضائع کرنے سے روکتا ہے۔ بڑی فہرستیں سکرول کرتے وقت یا زوم کرتے وقت خاص طور پر موثر: 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(bitmap) کے ذریعے Bitmap کے لیے Canvas بنایا جا سکتا ہے اور کسی بھی ثیرڈ پر اس پر کھینچا جا سکتا ہے۔ یہ پس منظر میں پیچیدہ گرافکس کو پھلے سے تیار کرنے کے لیے استعمال ہوتا ہے۔ تاہم، onDraw کو بھیجا گیا Canvas سیسٹم کا ہے اور صرف onDraw میتھڈ کے اندر UI ثیرڈ پر استعمال کیا جا سکتا ہے۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں