Android-এ Canvas — এটি android.graphics প্যাকেজের একটি ক্লাস যা View-তে 2D রেন্ডারিংয়ের জন্য API সরবরাহ করে। Canvas একটি ক্যানভাসের মতো কাজ করে যার উপর ডেভেলপার বিভিন্ন draw* পদ্ধতি ব্যবহার করে জ্যামিতিক আকার, টেক্সট, ছবি এবং পাথ আঁকে। Android ডেভেলপারস ডকুমেন্টেশন (2025) অনুসারে, Canvas হল Android-এ কাস্টম রেন্ডারিংয়ের প্রাথমিক টুল এবং এটি Paint ক্লাসের সাথে স্টাইল এবং রঙ নির্ধারণের জন্য ব্যবহৃত হয়। প্রতিটি onDraw() কল View-এর বিটম্যাপ বাফারের সাথে যুক্ত একটি প্রস্তুত Canvas ইনস্ট্যান্স পায়।
মূল বিষয়
Canvas — Android-এ কেন্দ্রীয় 2D গ্রাফিক্স ক্লাস যা একটি প্লেনে আঁকার জন্য পদ্ধতি সরবরাহ করে। প্রতিটি Canvas একটি Bitmap-এর সাথে সংযুক্ত — একটি মেমরি এলাকা যেখানে অঙ্কন অপারেশনের ফলাফল রেকর্ড করা হয়। যখন একটি View পুনরায় আঁকা হয়, সিস্টেম onDraw()-এ একটি Canvas পাস করে যা ইতিমধ্যেই সেই View-এর বাফারের সাথে যুক্ত।
Canvas একটি কোঅর্ডিনেট সিস্টেমে কাজ করে যেখানে (0,0) উপরের বাম কোণ, X অক্ষ ডানে যায়, Y অক্ষ নিচে যায়। সমস্ত অঙ্কন অপারেশন Canvas-এর বর্তমান অবস্থা ব্যবহার করে, যার মধ্যে রূপান্তর ম্যাট্রিক্স, ক্লিপিং এলাকা এবং Paint স্টাইল অন্তর্ভুক্ত। Android ডকুমেন্টেশন (2025) অনুসারে, Canvas API-তে বিভিন্ন ধরনের গ্রাফিক প্রিমিটিভের জন্য 30টিরও বেশি draw* পদ্ধতি অন্তর্ভুক্ত রয়েছে।
Android 3.0 (API 11) থেকে Canvas DisplayList-এর মাধ্যমে হার্ডওয়্যার এক্সিলারেশন সমর্থন করে। এক্সিলারেটেড মোডে, Canvas অপারেশনগুলি DisplayList-এ রেকর্ড করা হয় এবং তারপর GPU-তে সম্পাদিত হয়। এটি উল্লেখযোগ্য কর্মক্ষমতা লাভ দেয় কিন্তু সীমাবদ্ধতা আরোপ করে: কিছু Canvas অপারেশন (অ-পাথ ক্লিপ সহ clipPath) এক্সিলারেটেড মোডে সমর্থিত নয়।
Canvas মৌলিক প্রিমিটিভ আঁকার জন্য পদ্ধতির একটি সেট সরবরাহ করে। প্রতিটি পদ্ধতি জ্যামিতিক প্যারামিটার এবং একটি Paint অবজেক্ট গ্রহণ করে যা ভিজ্যুয়াল স্টাইল নির্ধারণ করে।
| পদ্ধতি | উদ্দেশ্য | উদাহরণ |
|---|---|---|
| drawRect() | আয়তক্ষেত্র আঁকে | canvas.drawRect(10f, 10f, 100f, 100f, paint) |
| drawCircle() | বৃত্ত আঁকে | canvas.drawCircle(50f, 50f, 30f, paint) |
| drawLine() | রেখা আঁকে | canvas.drawLine(0f, 0f, 100f, 100f, paint) |
| drawText() | টেক্সট আঁকে | canvas.drawText(“Hello”, 10f, 20f, paint) |
| drawBitmap() | ছবি আঁকে | canvas.drawBitmap(bitmap, 0f, 0f, paint) |
| drawPath() | ইচ্ছামতো পাথ আঁকে | canvas.drawPath(path, paint) |
| drawOval() | ডিম্বাকৃতি আঁকে | canvas.drawOval(rectF, paint) |
| drawArc() | চাপ বা সেক্টর আঁকে | canvas.drawArc(rectF, 0f, 90f, true, paint) |
প্রতিটি পদ্ধতি যেকোনো ক্রমে কল করা যেতে পারে — Canvas কলের ক্রমে আঁকে, আগের উপাদানগুলোর উপর নতুন উপাদান স্তরিত করে। জটিল কম্পোজিশনের জন্য, Canvas অবস্থা সংরক্ষণ এবং পুনরুদ্ধার সহ মাল্টি-লেয়ার রেন্ডারিং কৌশল ব্যবহার করা হয়।
Paint — এটি সেই ক্লাস যা নির্ধারণ করে কীভাবে Canvas আঁকবে। Paint ছাড়া, Canvas পদ্ধতি অকেজো — এটি রঙ, রেখার পুরুত্ব, ভরাট স্টাইল, টেক্সট আকার, প্রভাব (ছায়া, গ্রেডিয়েন্ট, অস্পষ্টতা) এবং ব্লেন্ডিং মোড সেট করে।
Paint-এর মূল বৈশিষ্ট্য: color (রঙ), style (FILL, STROKE বা FILL_AND_STROKE), strokeWidth (রেখার পুরুত্ব), textSize (টেক্সট আকার), isAntiAlias (অ্যান্টি-অ্যালিয়াসিং), shader (গ্রেডিয়েন্ট বা ছবি)। একটি Paint অবজেক্ট তৈরি করা একটি ব্যয়বহুল অপারেশন, তাই এটি একবার তৈরি করে পুনরায় ব্যবহার করা উচিত।
private val fillPaint = Paint().apply {
color = Color.parseColor("#FF6200EE")
style = Paint.Style.FILL
isAntiAlias = true
}
private val strokePaint = Paint().apply {
color = Color.WHITE
style = Paint.Style.STROKE
strokeWidth = 4f
isAntiAlias = true
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.drawCircle(100f, 100f, 80f, fillPaint)
canvas.drawCircle(100f, 100f, 80f, strokePaint)
}
এই উদাহরণে, দুটি Paint অবজেক্ট ব্যবহার করা হয়েছে: একটি বৃত্তটি বেগুনি রঙে ভরাট করার জন্য, দ্বিতীয়টি সাদা রেখার জন্য। ভরাট এবং রেখা আলাদা করা একটি মানক অনুশীলন যা অবজেক্ট পুনরায় তৈরি না করেই চেহারার নমনীয় নিয়ন্ত্রণ দেয়।
গ্রেডিয়েন্ট ভরাটের জন্য, Paint একটি Shader গ্রহণ করে — উপশ্রেণী LinearGradient, RadialGradient, SweepGradient। Shader setShader() পদ্ধতির মাধ্যমে Paint-এর সাথে সংযুক্ত হয় এবং নির্ধারণ করে কিভাবে রঙ অঙ্কন এলাকা জুড়ে পরিবর্তিত হয়।
Canvas কোঅর্ডিনেট সিস্টেমের ম্যাট্রিক্স রূপান্তর সমর্থন করে: translate() (স্থানান্তর), rotate() (ঘূর্ণন), scale() (স্কেলিং) এবং skew() (বাঁকানো)। রূপান্তরগুলি জমা হয়: প্রতিটি পরবর্তী কল আগেরগুলোর উপর প্রয়োগ হয়।
রূপান্তর স্ট্যাক পরিচালনা save() এবং restore()-এর মাধ্যমে করা হয়। save() বর্তমান Canvas অবস্থা (ম্যাট্রিক্স, ক্লিপ) স্ট্যাকে সংরক্ষণ করে, restore() শেষ সংরক্ষিত অবস্থা পুনরুদ্ধার করে। save() এবং restore()-এর মধ্যে নেস্টেড রূপান্তর প্রয়োগ করা যেতে পারে।
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.save() // Save initial state
canvas.translate(100f, 100f) // Translate origin
// First square
canvas.drawRect(0f, 0f, 50f, 50f, fillPaint)
canvas.save() // Save after translate
canvas.rotate(45f, 25f, 25f) // Rotate around square center
// Rotated square
canvas.drawRect(0f, 0f, 50f, 50f, strokePaint)
canvas.restore() // Restore after rotate
canvas.restore() // Restore initial state
}
সর্বদা রূপান্তর শুরু করার আগে save() এবং সেগুলি সম্পূর্ণ করার পরে restore() ব্যবহার করুন। ভারসাম্যহীন save/restore ম্যাট্রিক্স জমা এবং পরবর্তী উপাদানগুলির ভুল রেন্ডারিংয়ের দিকে নিয়ে যায়।
জটিল গ্রাফিক্সের জন্য, Canvas-কে Bitmap এবং Path-এর সাথে একত্রিত করা হয়। Bitmap ছবি লোড এবং রেন্ডার করা ফ্রেম ক্যাশ করার জন্য ব্যবহৃত হয়। Path ইচ্ছামতো বেজিয়ার বক্ররেখা, বহুভুজ এবং জটিল কনট্যুর তৈরির জন্য ব্যবহৃত হয়।
অফস্ক্রিন রেন্ডারিং কৌশল: একটি Bitmap তৈরি করা হয়, তার উপর একটি পৃথক Canvas-এর মাধ্যমে একটি জটিল দৃশ্য আঁকা হয়, এবং তারপর প্রস্তুত Bitmapটি drawBitmap()-এর মাধ্যমে onDraw()-এ আউটপুট করা হয়। এটি প্রতিটি ফ্রেমে সম্পূর্ণ পুনরায় অঙ্কন ছাড়াই জটিল গ্রাফিক্স আপডেট করার অনুমতি দেয়।
private var offscreenBitmap: Bitmap? = null
private var offscreenCanvas: Canvas? = null
fun buildOffscreenScene(width: Int, height: Int) {
offscreenBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
offscreenCanvas = Canvas(offscreenBitmap)
// Render scene once
offscreenCanvas!!.drawColor(Color.WHITE)
drawGrid(offscreenCanvas!!)
drawComplexShape(offscreenCanvas!!)
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
offscreenBitmap?.let { canvas.drawBitmap(it, 0f, 0f, null) }
}
Path জটিল কনট্যুর তৈরির জন্য ব্যবহৃত হয়: বেজিয়ার বক্ররেখা (quadTo, cubicTo), চাপ (arcTo), রেখা (lineTo)। Path ভর্তি আকারের জন্য বন্ধ (close()) বা রেখার জন্য খোলা থাকতে পারে। প্রধান drawPath() পদ্ধতি চূড়ান্ত রেন্ডারিংয়ের জন্য Path এবং Paint একত্রিত করে।
Canvas রেন্ডারিং কর্মক্ষমতা সরাসরি অ্যাপ্লিকেশন FPS-কে প্রভাবিত করে। প্রধান সমস্যা: onDraw()-এ অত্যধিক বরাদ্দ, ঘন ঘন invalidate() কল এবং হার্ডওয়্যার এক্সিলারেশনের অপ-ইষ্টক ব্যবহার।
Paint, Path, Rect, RectF এবং অন্যান্য অবজেক্ট একবার ইনিশিয়ালাইজার বা setup() পদ্ধতিতে তৈরি করা উচিত। onDraw()-এ প্রতিটি বরাদ্দ গার্বেজ কালেক্টরের উপর চাপ সৃষ্টি করে, যা মাইক্রো-ল্যাগের দিকে নিয়ে যায়। ব্যতিক্রম হল অপরিবর্তনীয় অবজেক্টের জন্য static বা companion object।
যদি অধিকাংশ View দৃশ্যমান এলাকার বাইরে লুকানো থাকে (উদাহরণস্বরূপ, ScrollView-এ), রেন্ডারিং সীমিত করতে canvas.clipRect() ব্যবহার করুন। এই ক্ষেত্রে হার্ডওয়্যার এক্সিলারেশন অদৃশ্য পিক্সেলের ক্লিপিং অতিরিক্তভাবে অপ্টিমাইজ করে।
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// Clip to visible area
canvas.save()
canvas.clipRect(scrollX, scrollY, scrollX + width, scrollY + height)
// Render large scene
renderScene(canvas)
canvas.restore()
}
যে Views-এ জটিল Canvas গ্রাফিক্স রয়েছে এবং যা খুব কমই আপডেট হয়, তাদের জন্য LAYER_TYPE_HARDWARE সহ View.setLayerType() ব্যবহার করুন। ঘন ঘন আপডেট হওয়া অ্যানিমেশনের জন্য, ব্যয়বহুল হার্ডওয়্যার স্তর আপডেট এড়াতে LAYER_TYPE_NONE ব্যবহার করুন। GPU Profile Rendering এবং Android Studio Profiler ব্যবহার করে প্রোফাইল করুন।
প্রায়শই জিজ্ঞাসিত প্রশ্ন
হ্যাঁ, আপনি Canvas(Bitmap) তৈরি করতে পারেন — একটি কনস্ট্রাক্টর যা Bitmap গ্রহণ করে। এটি অফস্ক্রিন রেন্ডারিংয়ের জন্য ব্যবহৃত হয়: আপনি Bitmap-এ আঁকেন, তারপর এটি drawBitmap()-এর মাধ্যমে আউটপুট করেন। Canvas Surface (SurfaceView-এর জন্য) বা Picture-এর মাধ্যমেও তৈরি করা যেতে পারে।
Canvas — UI থ্রেডে View-তে আঁকার জন্য API। SurfaceView — একটি পৃথক Surface যা নিজস্ব Canvas (lockCanvas() / unlockCanvasAndPost()) এর মাধ্যমে ব্যাকগ্রাউন্ড থ্রেড থেকে আপডেট হতে পারে। SurfaceView গেম এবং ভিডিওর জন্য পছন্দনীয়।
সবচেয়ে সাধারণ কারণ হল ভারসাম্যহীন save() এবং restore()। যদি রূপান্তরের (translate, rotate) পরে restore() কল না করা হয়, তাহলে Canvas একটি পরিবর্তিত কোঅর্ডিনেট সিস্টেমে থাকে এবং পরবর্তী উপাদানগুলি অফসেট সহ আঁকা হয়। আপনার save()/restore() জোড়া পরীক্ষা করুন।
অনুভূমিক সেন্টারিংয়ের জন্য Paint.setTextAlign(Paint.Align.CENTER) এবং উল্লম্বের জন্য Paint.getTextBounds() বা Paint.descent() / ascent() ব্যবহার করুন। সেন্টারিং: canvas.drawText(টেক্সট, centerX, centerY - (ascent + descent) / 2, paint)।
Canvas নিজে অ্যানিমেট করে না — এটি শুধু বর্তমান অবস্থা আঁকে। অ্যানিমেশন invalidate() (বা postInvalidateOnAnimation()) এর ধারাবাহিক কলের মাধ্যমে অর্জিত হয়, প্রতিবার onDraw()-এ একটি নতুন ফ্রেম আঁকে। মসৃণ অ্যানিমেশনের জন্য Vsync-এর সাথে সিঙ্ক করতে ValueAnimator বা Choreographer ব্যবহার করুন।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন