Custom Adapter ( Android Bangla Tutorial -14)
এই পর্বে আমরা দেখবো কিভাবে আমরা ইচ্ছামত Adapter তৈরি করতে পারি । এর আগে আমরা ArrayAdapter নিয়ে কাজ করেছি যেখানে একটি অ্যারে কে নিয়ে কাজ করা যেত কিন্তু এখন আমরা একটি লিস্ট তৈরি করবো যেখানে প্রতি লিস্টের ভিতর একাধিক ভিউ থাকবে । একাধিক অ্যারে থেকে ডাটা আসবে ।
ধরুন কয়েকটি কোম্পানির লোগো , তাদের অফিস ও প্রতিষ্ঠার বছর এক লিস্টে দেখানো হবে । দেখতে এরকম -
তো চলুন প্রথমে লেআউট এর ডিজাইন করা যাক -
আপনি যেসকল ইমেজ দিতে চান সেগুলোর রাইট বাটনে ক্লিক করে কপি করে drawable ফাইলে রাইট বাটনে ক্লিক করে পেস্ট করে ওকে প্রেস করুন । ছবির নামের ভিতরে কোন জায়গায় কোন বড় হাতের অক্ষর থাকতে পারবে নাহ এবং প্রথমে কোন সংখ্যা থাকতে পারবে নাহ ।
এবার যেসব জায়গার নাম ও বছর লিখতে চাই সেগুলো strings.xml ফাইলের ভিতর লিখে দিব । এরকম দুইটা স্ট্রিং অ্যারে ডিক্লার করে -
এখানে প্রথমে অ্যাপের নাম বাই ডিফল্ট দেয়া আছে । এরপর আরো ৩ টি স্ট্রিং লেখা আছে যা আমি কোডের বিভিন্ন জায়গায় ইউজ করেছি বলে লিখেছি । এই লেখাগুলো লিস্টে ভিউ আইটেম তৈরি করার সময় কিভাবে ভিউ তৈরি হচ্ছে তা দেখার জন্য ইউজ করা হইছে ।
কোডের ইমেজও দেয়া হল -
এখন লেআউট ডিজাইন করা যাক ।এবার যে এক্টিভিটি তে লিস্টভিউ দেখাতে চাই সেখানে লিস্টভিউ তৈরি করবো ।
এখন প্রতিটি লেআউট কিরকম হবে সেটি ডিজাইন করবো । প্রতি লেআউট এ আমরা ৩টি জিনিস রেখেছি । ইমেজ , ঠিকানা এবং বছর । তো প্রতি লিস্টের ভিউ এর জন্য একটা আলাদা ডিজাইন ফাইল খুলতে হবে । এজন্য res -> layout উপর রাইট ক্লিক করে -> New -> Layout resource file এ ক্লিক করুন ।
এবার ফাইলের একটি নাম দিয়ে OK প্রেস করুন । আমি নাম দিলাম singlelistlayout । এখানে ফাইলের নামে কোন বড় হাতের অক্ষর দেয়া যাবে নাহ ।
এবার আমাদের একটি লিস্ট ভিউতে কি কি থাকবে সেগুলোর ভিউ দিয়ে দেয়া যাক -
লেআউট ফাইল ওপেন করার সাথে আমরা যে ভিউটা দেখতে পাবো -
দেখুন এখানে layout_height="match_parent" দেয়া আছে , আমরা লিস্টের ১ টি সিঙ্গেল ভিউয়ের ডিজাইন করছি, এখন লিস্টের সিঙ্গেল ১টি ভিউ এর হাইট যদি পুরো স্ক্রিন জুড়ে থাকে তাহলে সেটা নিশ্চয়ই ভালো দেখাবে নাহ ।অবশ্য এভাবে match_parent রাখলে লিস্টগুলো খুব ছোট ছোট হয়ে আসবে। তাই layout_height="80dp" দিয়ে দিলাম (ইচ্ছামত)। এখন ৬ নম্বর লাইনে কার্সর রেখে লেখা আরম্ভ করি -
লেখা শুরু করার আগে দেখা যাক , আমরা যে ভিউ তৈরি করবো সেটি করকম। এখানে ৩টি ভিউ পাশাপাশি এবং তাদের নিচে দাগ কাটার মত ১টি ভিউ আছে যাতে প্রতিটি ভিউ আলাদা ভাবে দেখা যায় । আমরা জানি লিনিয়ার লেআউট হয় পাশাপাশি নয়তো উপর-নিচ কাজ করে, কিন্তু এখানে ২টাই আছে । তাহলে উপরের ভিউগুলোকে পাশাপাশি একটা লিনিয়ার লেআউট এ রেখে নিচের দাগ কাটা ভিউকে রুট লেআউট এর সাথে উপর-নিচ করে রাখতে পারি । এটা রিলেটিভ লেআউট দিয়ে করাই বেটার , তবু দেখা যাক কিভাবে আমরা ১ এর অধিক লেআউট ইউজ করবো ।
প্রথমে একটি লিনিয়ার লেআউট তৈরি করে তার ভিতর ১টি ইমেজভিউ ও ২টি টেক্সভিউ তৈরি করা যাক -
<LinearLayout
android:layout_width="match_parent"
android:layout_height="80dp"
android:orientation="horizontal" >
// এখানে height="80dp" দিয়ে দিলাম । আপনি আপনার ইচ্ছামত হাইট দিতে পারেন । অর্থাৎ আমাদের লিস্টের প্রতিটি ভিউ এর width পুরো স্ক্রিন জুড়ে এবং হাইট 80dp করে হবে । এবং orientation="horizontal" অর্থাৎ ভিউগুলো পাশাপাশি বসবে
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<TextView
android:id="@+id/location"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<TextView
android:id="@+id/year"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
প্রতি ভিউতে width, height ও id দিয়ে দিলাম ।
এখন উপরের ভিউগুলোতে আরো কিছু এড ও অদল-বদল করবো । প্রথমে প্রতি ভিউগুলোর android:layout_width="0dp" করে সাথে android:layout_weight="1" যোগ করে দিন । weight="1"ফলে যা হল আমাদের প্রতি ভিউ ফুল স্ক্রিনের ১ ভাগ করে নিভে । এখানে ৩ টি ভিউ আছে, তাই ফুল স্ক্রিন ৩ ভাগে ভাগ হইছে । আপনি আপনার ইছহামত যত ইচ্ছা ভাগে ভাগ করতে পারেন । ধরুন আমি ধরলাম মোট ৪ ভাগ আর ইমেজ ভিউ তে weight="2" দিয়ে বাকি ২ টা টেক্সভিউ weight="1" দিলাম । তার মানে মোট স্ক্রিনের অর্ধেক ইমেজ ভিউ নিয়ে বাকি অর্ধেক ২টা টেক্সভিউ ১ ভাগ ১ ভাগ করে নিবে । আর যেহেতু এটা আমরা পাশাপাশি ভাগ করেছি তাই layout_width="0dp" দিয়ে দিতে হবে । যদি উপর-নিচ ভাগ করতাম তবে android:layout_height="0dp" দিয়ে দিতাম । আরো যা এড করতে হবে -
<LinearLayout
android:layout_width="match_parent"
android:layout_height="78dp"
android:orientation="horizontal" >
<ImageView
android:id="@+id/imageView"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:src = "@drawable/sajibA"
android:contentDescription="@string/a_single_image"
/>
// src ফাইল দিয়ে ইমেজ বসালাম শুধু দেখার জন্য যে আমার লেআউট কিভাবে ডিজাইন হচ্ছে । contentDescription দিয়ে ইমেজের একটা বর্ণনা দিয়ে দিলাম , যদি কোন কারনে ইমেজ শো নাহ করে তবে বর্ণনাটুকু দেখাবে ।
<TextView
android:id="@+id/location"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/mirpur"
/>
// ইমেজের মত সেইম ভাবে টেক্স দেখার জন্য একটি টেক্স লিখে নিলাম আর সেটি যাতে মাঝখানে দেখা যায় তাই gravity="center" দিয়ে দিলাম
<TextView
android:id="@+id/year"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/2017"
/>
</LinearLayout>
উপরের ভিউগুলো থাকবে পাশাপাশি এবং এদের নিচে যে দাগ কাটা থাকবে যাতে এক ভিউ থেকে অন্য ভিউ আলাদা বুঝা যায় , সেজন্য আমরা ভিউ ট্যাগটি ব্যাবহার করবো -
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="@color/colorPrimary"
></View>
// ভিউ এর width টা ফুল স্ক্রিন জুড়ে আর height দিলাম ২ ডিপি কারন আমাদের রুট লিনিয়ার লেআউট এর হাইট ৮০ ডিপি আর উপরে ৩টা ভিউ এর লেআউট আর হাইট ৭৮ ডিপি , বাকি থাকে ২ ডিপি , সেই ২ ডিপি এখানে দিয়ে দিলাম । তাহলে আমাদের কোড আর ভিউটা দেখতে যেরকম হবে -
এবার জাভা ক্লাসে যাওয়া যাক -
public class MainActivity extends AppCompatActivity{
ListView listView;
// প্রথমে লিস্টভিউ এর একটি অব্জেক্ট তৈরি করে xml ফাইলের লিস্টভিউ এর আইডির সাথে এড করে দেই । মনে রাখতে হবে আমরা অব্জেক্ট তৈরি করে ক্লাস এর ভিতর আর xml এর ভিউগুলোর সাথে এড করি onCreate ম্যাথডের ভিতর ।
int[] imageView = {R.drawable.SajibA, R.drawable.SajibB , R.drawable.SajibC,
R.drawable.SajibD , R.drawable.SajibE };
// এখানে আমরা যে ইমেজগুলো নিয়েছি তার অ্যারেলিস্ট তৈরি করলাম । ইমেজগুলো নিতে হবে int অ্যারে তে ।
String[] location;
String[] year;
// এই স্ট্রিং অ্যারে এর ভিতর এ strings.xml যে স্ট্রিং রিসোর্স গুলো দিয়েছি সেগুলোর সাথে সংযোগ করে দিব
@Override
protected void Oncreate(Bundle savedInstanceState) {
super.onCreate(saveInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listView);
location = getResources().getStringArray(R.array.location);
year = getResources().getStringArray(R.array.year);
// xml এর লিস্টভিউ এর আইডির সাথে লিস্টভিউ এর অব্জেক্ট এড করে দিলাম । স্ট্রিং অ্যারের সাথে স্ট্রিং রিসোর্স এড করে দিলাম ।
}
}
এখানে আমাদের আরো একটি জাভা ক্লাসের প্রয়োজন । কেননা এর আগে আমরা একটি মাত্র ভিউ নিয়ে কাজ করেছি । কিন্তু এখানে যেহেতু ৩টি ভিউ তাই এগুলোকে একসাথে রাখার জন্য আর একটি জাভা ক্লাস লাগবে । এটি একটি লেআউট লিস্টের জন্য ডাটা সাপ্লাই হিসেবে কাজ করবে । আমাদের ভিউতে থাকা ইমেজ ও টেক্স রিসোর্স গুলো এই ক্লাসের মাধ্যমে বাইন্ড হয়ে সেটি ভিউতে গিয়ে ডিসপ্লে হবে ।
তো একটি জাভা ক্লাস খুলুন । এটির নাম DataProvider দিয়ে ওকে বাটন ক্লিক করুন । আপনি ইচ্ছামত যেকোন নাম দিতে পারেন ।
নতুন জাভা ক্লাসে রিসোর্স ৩টির ভ্যারিয়েবল ডিক্লার করুন । এরপর ক্লাসের ভিতর কার্সর রেখে Alt+Insert চাপলে দেখবেন Generate ফর্ম দেখাচ্ছে । এখান থেকে Constructor এবং Getter and Setter এ ক্লিক করে ইমপ্লিমেন্ট করে নিন ।
দুই ক্ষেত্রেই ইমপ্লিমেন্ট করার সময় Ctrl চেপে ধরে সবগুলো সিলেক্ট করে নিয়ে ওকে প্রেস করবেন ।
তাহলে আমরা যে ভিউ দেখতে পাবো ডাটা প্রোভাইডার ক্লাসে -
এখন এই ডাটা প্রোভাইডার এর ৫টি অব্জেক্ট তৈরি করবো কেননা আমরা ৫টি ভিউলিস্ট দেখাতে চাই । এখন আবার মেইন এক্টিভিটি তে ফিরে যান ।
public class MainActivity extends AppCompatActivity{
ListView listView;
int[] imageView = {R.drawable.SajibA, R.drawable.SajibB , R.drawable.SajibC,
R.drawable.SajibD , R.drawable.SajibE };
String[] location;
String[] year;
@Override
protected void Oncreate(Bundle savedInstanceState) {
super.onCreate(saveInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listView);
location = getResources().getStringArray(R.array.location);
year = getResources().getStringArray(R.array.year);
// এই পর্যন্ত কোড আগেই করা ছিল
int i=0;
for(String locations:location){
DataProvider dataProvider = new DataProvider(imageView[i],locations,year[i]);
i++;
// এটি ফরইচ লুপ । লুপের ভিতর ডাটা প্রোভাইডার এর একটি অব্জেক্ট তৈরি করে দিলাম ।এতে কন্সট্রাকটর হিসেবে ইমেজভিউ , লোকেশন ও আইডি পাস করলাম । ইমেজভিউ ও ইয়ারে i=0 দিয়ে ইনিশিয়ালাইজ করার মানে লুপের মাধ্যমে ৫টি অব্জেক্ট তৈরি করবে । আর লোকেশন এ প্রয়োজন হয় নাই কারন ফরইচ লুপ অনুযায়ী আপনি যে প্যারামিটার এই ফরইচ লুপ এর ভিতরে দিবেন সেটির সব ভ্যারিয়েবল গুলো একে একে চলে আসে । এখানে ফরইচ লুপের ভিতর আমরা লোকেশন দিয়ে দিয়েছি তাই লোকেশন এর সবগুলো অটোমেটিক চলে আসছে । আপনি চাইলে যে কোন একটি ব্যাবহার করতে পারেন ।
}
}
}
এখন আমাদের এডাপ্টর তৈরি করতে হবে । এর জন্য চাই আরো একটি জাভা ক্লাস । আগের জাভা ক্লাসের মাধ্যমে আমরা ডাটা গুলোকে একসাথে বেধে রেখেছি এবং যে কয়টি লিস্ট দরকার সেকয়টি অব্জেক্ট তৈরি করেছি আর এখন নতুন এক জাভা ক্লাসের মাধ্যমে সেই এক একটি বাধা বস্তা আমরা লেআউট এর ভিতরে নিয়ে যাবো । নতুন জাভা ক্লাসের নাম দিলাম DataAdapter
এখানে DataAdapter ক্লাসে extends করলাম ArrayAdapter , যেহেতু আমার ডাটাগুলো অ্যারে হয়ে আসতেছে । extends করার সময় ইরর দেখাবে তখন পাশের লাল বাল্ব এর উপর ক্লিক করলেই দেখবেন Create Constructor maching super দেখাছে , সেখানে ক্লিক করে প্রথম যে কন্সট্রাকর টি দেখাছে ২টি প্যারামিটার সহ সেটি ক্লিক করে ওকে প্রেস করুন ।
ডাটা প্রোভাইডার এর প্রত্যেক অব্জেক্ট Adapter এ সংযুক্ত করতে add ম্যাথড টি লিখে নিন । add লিখলেই দেখবেন চলে আসবে ।
এরপর এই অবজেক্টগুলো নিয়ে একটি লিস্ট তৈরি করার জন্য List ক্লাসের একটি অব্জেক্ট তৈরি করুন -
আমরা লিস্টের মাধ্যমেই পুরো ভিউটা ইন্টারফেস এ দেখাবো । এখন লিস্টে যে ডাটা আসবে সেটি কোথা থেকে আসবে ? ডাটা তো আছে ডাটা প্রোভাইডার এর মধ্যে । তাহলে আবার একটু মেইন এক্টিভিটি তে যেতে হবে । ডাটা প্রোভাইডার এর যে ৫টি অব্জেক্ট তৈরি করেছিলাম সেখান থেকে ডাটা নিয়ে আসতে হবে -
public class MainActivity extends AppCompatActivity{
ListView listView;
int[] imageView = {R.drawable.SajibA, R.drawable.SajibB , R.drawable.SajibC,
R.drawable.SajibD , R.drawable.SajibE };
String[] location;
String[] year;
DataAdapter adapter;
// DataAdapter ক্লাসের একটি অব্জেক্ট কল করলাম
@Override
protected void Oncreate(Bundle savedInstanceState) {
super.onCreate(saveInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listView);
location = getResources().getStringArray(R.array.location);
year = getResources().getStringArray(R.array.year);
adapter = new DataAdapter(this,R.layout.singlelistlayout);
listView.setAdapter(adapter);
// DataAdapter এর অব্জেক্ট তৈরি করলাম । মনে আছে কি DataAdapter ক্লাসে বাই ডিফল্ট একটা কন্সট্রাক্টর লিখতে হয়েছিল ২টি প্যারামিটার সহ । তো প্যারামিটার হিসেবে এখানে কনটেক্স ও যে লেআউট দেখাতে চাই সেটি পাস করতে হবে । যেহেতু এই এক্টিভিটি তেই আমরা লেআউট দেখাবো তাই কনটেক্স হিসেবে this কিংবা getBaseContext() কিংবা getApplicationContext() একটা লিখলেই হবে আর লেআউট এর নাম লিখে দিলাম । এই প্রোগ্রামে আমার একটিভিটি ক্লাস কিন্তু একটা জাভা ক্লাস ২ টা । জাভা ক্লাস ২টা কিন্তু একটিভিটি ক্লাস নাহ । এক্টিভিটি ক্লাস মানে যে ক্লাসের সাথে লেআউট থাকবে ।
// এর পরের লাইনে এই এক্টিভিটি ক্লাসে যে লিস্টভিউ অব্জেক্ট আছে সেটির সাথে এড করে দিলাম । কারন Adapter এর সাহায্যেই তো ডাটাগুলো এখানে এসে শো করবে । আর এই লাইন ২টি অবশ্যই ফরইচ লুপের উপরে হতে হবে ।
int i=0;
for(String locations:location){
DataProvider dataProvider = new DataProvider(imageView[i],locations,year[i]);
adapter.add(dataProvider);
// প্রতিবার DataProvider এর একটি অব্জেক্ট তৈরি হবে এবং সেই ডাটা adapter.add ম্যাথডের মাধ্যমে ডাটা এডাপ্টর ক্লাসে চলে যাবে ।
i++;
}
}
}
মেইন এক্টিভিটি তে আর কোন কাজ নেই । আবার DataAdapter ক্লাসে চলে আসুন -
উপরে add ম্যাথডের মধ্যে ডাটা পাস করেছি । তো DataAdapter এর এড ম্যাথডের ভিতর , DataAdapter এ তৈরি করা লিস্টের সাথে সংযুক্ত করতে লিখে দিন - এই ক্লাসের কোডটা হবে -
এখন আরো একটি ম্যাথড এড করতে হবে -
সেটি হল ভিউ ম্যাথড । আমরা ডাটাও নিয়ে আসলাম , তার লিস্টও তৈরি করলাম কিন্তু কোন ডাটা কোন ভিউতে থাকবে সেটা সেট করে দিতে হবে । তো ডাটা কে কন্ট্রোল করতে এখানেই একটি স্ট্যাটিক ক্লাস তৈরি করি -
এখন ভিউ ম্যাথড টা লিখা যাক -
ব্যাস , কাজ শেষ । এবার প্রজেক্টি রান করুন 😊😊😊
তাহলে আমাদের যে ফাইনাল ভিউটি দাঁড়ালো -
এখানে কোন ভিউতে ক্লিক করলে কিছু দেখাবে নাহ কারন তার কোন কোড আমরা লিখি নাই 😊
শেষ এ আরেকবার রিভিউ দিচ্ছি , আমাদের মোট ৩ টি ক্লাস এবং ২ টি xml ফাইল । প্রতি ক্লাসের কোডগুলো আবার দিয়ে দিচ্ছি -
strings.xml -
activity_main.xml -
singlelistlayout.xml -
MainActivity.java -
DataAdapter.java -
DataProvider.java -
Thank You 😊😊😊😊😊😊😊😊😊😊😊😊😊😊
ধরুন কয়েকটি কোম্পানির লোগো , তাদের অফিস ও প্রতিষ্ঠার বছর এক লিস্টে দেখানো হবে । দেখতে এরকম -
তো চলুন প্রথমে লেআউট এর ডিজাইন করা যাক -
আপনি যেসকল ইমেজ দিতে চান সেগুলোর রাইট বাটনে ক্লিক করে কপি করে drawable ফাইলে রাইট বাটনে ক্লিক করে পেস্ট করে ওকে প্রেস করুন । ছবির নামের ভিতরে কোন জায়গায় কোন বড় হাতের অক্ষর থাকতে পারবে নাহ এবং প্রথমে কোন সংখ্যা থাকতে পারবে নাহ ।
এবার যেসব জায়গার নাম ও বছর লিখতে চাই সেগুলো strings.xml ফাইলের ভিতর লিখে দিব । এরকম দুইটা স্ট্রিং অ্যারে ডিক্লার করে -
<resources>
<string name="app_name">Mashiur Rahman</string>
<string name="an_single_image">An single image</string>
<string name="mirpur">Mirpur</string>
<string name="_2016">2016</string>
<string-array name="location">
<item>Siddhersori</item>
<item>Dhaka</item>
<item>Mirpur</item>
<item>Barisal</item>
<item>Patuakhali</item>
</string-array>
<string-array name="year">
<item>2012</item>
<item>2013</item>
<item>2017</item>
<item>2016</item>
<item>2015</item>
</string-array>
</resources>
এখানে প্রথমে অ্যাপের নাম বাই ডিফল্ট দেয়া আছে । এরপর আরো ৩ টি স্ট্রিং লেখা আছে যা আমি কোডের বিভিন্ন জায়গায় ইউজ করেছি বলে লিখেছি । এই লেখাগুলো লিস্টে ভিউ আইটেম তৈরি করার সময় কিভাবে ভিউ তৈরি হচ্ছে তা দেখার জন্য ইউজ করা হইছে ।
কোডের ইমেজও দেয়া হল -
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.user.mashiurrahman.MainActivity">
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</LinearLayout>
এখন প্রতিটি লেআউট কিরকম হবে সেটি ডিজাইন করবো । প্রতি লেআউট এ আমরা ৩টি জিনিস রেখেছি । ইমেজ , ঠিকানা এবং বছর । তো প্রতি লিস্টের ভিউ এর জন্য একটা আলাদা ডিজাইন ফাইল খুলতে হবে । এজন্য res -> layout উপর রাইট ক্লিক করে -> New -> Layout resource file এ ক্লিক করুন ।
এবার ফাইলের একটি নাম দিয়ে OK প্রেস করুন । আমি নাম দিলাম singlelistlayout । এখানে ফাইলের নামে কোন বড় হাতের অক্ষর দেয়া যাবে নাহ ।
এবার আমাদের একটি লিস্ট ভিউতে কি কি থাকবে সেগুলোর ভিউ দিয়ে দেয়া যাক -
লেআউট ফাইল ওপেন করার সাথে আমরা যে ভিউটা দেখতে পাবো -
দেখুন এখানে layout_height="match_parent" দেয়া আছে , আমরা লিস্টের ১ টি সিঙ্গেল ভিউয়ের ডিজাইন করছি, এখন লিস্টের সিঙ্গেল ১টি ভিউ এর হাইট যদি পুরো স্ক্রিন জুড়ে থাকে তাহলে সেটা নিশ্চয়ই ভালো দেখাবে নাহ ।অবশ্য এভাবে match_parent রাখলে লিস্টগুলো খুব ছোট ছোট হয়ে আসবে। তাই layout_height="80dp" দিয়ে দিলাম (ইচ্ছামত)। এখন ৬ নম্বর লাইনে কার্সর রেখে লেখা আরম্ভ করি -
লেখা শুরু করার আগে দেখা যাক , আমরা যে ভিউ তৈরি করবো সেটি করকম। এখানে ৩টি ভিউ পাশাপাশি এবং তাদের নিচে দাগ কাটার মত ১টি ভিউ আছে যাতে প্রতিটি ভিউ আলাদা ভাবে দেখা যায় । আমরা জানি লিনিয়ার লেআউট হয় পাশাপাশি নয়তো উপর-নিচ কাজ করে, কিন্তু এখানে ২টাই আছে । তাহলে উপরের ভিউগুলোকে পাশাপাশি একটা লিনিয়ার লেআউট এ রেখে নিচের দাগ কাটা ভিউকে রুট লেআউট এর সাথে উপর-নিচ করে রাখতে পারি । এটা রিলেটিভ লেআউট দিয়ে করাই বেটার , তবু দেখা যাক কিভাবে আমরা ১ এর অধিক লেআউট ইউজ করবো ।
প্রথমে একটি লিনিয়ার লেআউট তৈরি করে তার ভিতর ১টি ইমেজভিউ ও ২টি টেক্সভিউ তৈরি করা যাক -
<LinearLayout
android:layout_width="match_parent"
android:layout_height="80dp"
android:orientation="horizontal" >
// এখানে height="80dp" দিয়ে দিলাম । আপনি আপনার ইচ্ছামত হাইট দিতে পারেন । অর্থাৎ আমাদের লিস্টের প্রতিটি ভিউ এর width পুরো স্ক্রিন জুড়ে এবং হাইট 80dp করে হবে । এবং orientation="horizontal" অর্থাৎ ভিউগুলো পাশাপাশি বসবে
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<TextView
android:id="@+id/location"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<TextView
android:id="@+id/year"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
প্রতি ভিউতে width, height ও id দিয়ে দিলাম ।
এখন উপরের ভিউগুলোতে আরো কিছু এড ও অদল-বদল করবো । প্রথমে প্রতি ভিউগুলোর android:layout_width="0dp" করে সাথে android:layout_weight="1" যোগ করে দিন । weight="1"ফলে যা হল আমাদের প্রতি ভিউ ফুল স্ক্রিনের ১ ভাগ করে নিভে । এখানে ৩ টি ভিউ আছে, তাই ফুল স্ক্রিন ৩ ভাগে ভাগ হইছে । আপনি আপনার ইছহামত যত ইচ্ছা ভাগে ভাগ করতে পারেন । ধরুন আমি ধরলাম মোট ৪ ভাগ আর ইমেজ ভিউ তে weight="2" দিয়ে বাকি ২ টা টেক্সভিউ weight="1" দিলাম । তার মানে মোট স্ক্রিনের অর্ধেক ইমেজ ভিউ নিয়ে বাকি অর্ধেক ২টা টেক্সভিউ ১ ভাগ ১ ভাগ করে নিবে । আর যেহেতু এটা আমরা পাশাপাশি ভাগ করেছি তাই layout_width="0dp" দিয়ে দিতে হবে । যদি উপর-নিচ ভাগ করতাম তবে android:layout_height="0dp" দিয়ে দিতাম । আরো যা এড করতে হবে -
<LinearLayout
android:layout_width="match_parent"
android:layout_height="78dp"
android:orientation="horizontal" >
<ImageView
android:id="@+id/imageView"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:src = "@drawable/sajibA"
android:contentDescription="@string/a_single_image"
/>
// src ফাইল দিয়ে ইমেজ বসালাম শুধু দেখার জন্য যে আমার লেআউট কিভাবে ডিজাইন হচ্ছে । contentDescription দিয়ে ইমেজের একটা বর্ণনা দিয়ে দিলাম , যদি কোন কারনে ইমেজ শো নাহ করে তবে বর্ণনাটুকু দেখাবে ।
<TextView
android:id="@+id/location"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/mirpur"
/>
// ইমেজের মত সেইম ভাবে টেক্স দেখার জন্য একটি টেক্স লিখে নিলাম আর সেটি যাতে মাঝখানে দেখা যায় তাই gravity="center" দিয়ে দিলাম
<TextView
android:id="@+id/year"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/2017"
/>
</LinearLayout>
উপরের ভিউগুলো থাকবে পাশাপাশি এবং এদের নিচে যে দাগ কাটা থাকবে যাতে এক ভিউ থেকে অন্য ভিউ আলাদা বুঝা যায় , সেজন্য আমরা ভিউ ট্যাগটি ব্যাবহার করবো -
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="@color/colorPrimary"
></View>
// ভিউ এর width টা ফুল স্ক্রিন জুড়ে আর height দিলাম ২ ডিপি কারন আমাদের রুট লিনিয়ার লেআউট এর হাইট ৮০ ডিপি আর উপরে ৩টা ভিউ এর লেআউট আর হাইট ৭৮ ডিপি , বাকি থাকে ২ ডিপি , সেই ২ ডিপি এখানে দিয়ে দিলাম । তাহলে আমাদের কোড আর ভিউটা দেখতে যেরকম হবে -
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="80dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="78dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/imageView"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:contentDescription="@string/an_single_image"/>
<TextView
android:id="@+id/location"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
/>
<TextView
android:id="@+id/year"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="@color/colorPrimary"></View>
</LinearLayout>
এবার জাভা ক্লাসে যাওয়া যাক -
public class MainActivity extends AppCompatActivity{
ListView listView;
// প্রথমে লিস্টভিউ এর একটি অব্জেক্ট তৈরি করে xml ফাইলের লিস্টভিউ এর আইডির সাথে এড করে দেই । মনে রাখতে হবে আমরা অব্জেক্ট তৈরি করে ক্লাস এর ভিতর আর xml এর ভিউগুলোর সাথে এড করি onCreate ম্যাথডের ভিতর ।
int[] imageView = {R.drawable.SajibA, R.drawable.SajibB , R.drawable.SajibC,
R.drawable.SajibD , R.drawable.SajibE };
// এখানে আমরা যে ইমেজগুলো নিয়েছি তার অ্যারেলিস্ট তৈরি করলাম । ইমেজগুলো নিতে হবে int অ্যারে তে ।
String[] location;
String[] year;
// এই স্ট্রিং অ্যারে এর ভিতর এ strings.xml যে স্ট্রিং রিসোর্স গুলো দিয়েছি সেগুলোর সাথে সংযোগ করে দিব
@Override
protected void Oncreate(Bundle savedInstanceState) {
super.onCreate(saveInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listView);
location = getResources().getStringArray(R.array.location);
year = getResources().getStringArray(R.array.year);
// xml এর লিস্টভিউ এর আইডির সাথে লিস্টভিউ এর অব্জেক্ট এড করে দিলাম । স্ট্রিং অ্যারের সাথে স্ট্রিং রিসোর্স এড করে দিলাম ।
}
}
এখানে আমাদের আরো একটি জাভা ক্লাসের প্রয়োজন । কেননা এর আগে আমরা একটি মাত্র ভিউ নিয়ে কাজ করেছি । কিন্তু এখানে যেহেতু ৩টি ভিউ তাই এগুলোকে একসাথে রাখার জন্য আর একটি জাভা ক্লাস লাগবে । এটি একটি লেআউট লিস্টের জন্য ডাটা সাপ্লাই হিসেবে কাজ করবে । আমাদের ভিউতে থাকা ইমেজ ও টেক্স রিসোর্স গুলো এই ক্লাসের মাধ্যমে বাইন্ড হয়ে সেটি ভিউতে গিয়ে ডিসপ্লে হবে ।
তো একটি জাভা ক্লাস খুলুন । এটির নাম DataProvider দিয়ে ওকে বাটন ক্লিক করুন । আপনি ইচ্ছামত যেকোন নাম দিতে পারেন ।
নতুন জাভা ক্লাসে রিসোর্স ৩টির ভ্যারিয়েবল ডিক্লার করুন । এরপর ক্লাসের ভিতর কার্সর রেখে Alt+Insert চাপলে দেখবেন Generate ফর্ম দেখাচ্ছে । এখান থেকে Constructor এবং Getter and Setter এ ক্লিক করে ইমপ্লিমেন্ট করে নিন ।
তাহলে আমরা যে ভিউ দেখতে পাবো ডাটা প্রোভাইডার ক্লাসে -
এখন এই ডাটা প্রোভাইডার এর ৫টি অব্জেক্ট তৈরি করবো কেননা আমরা ৫টি ভিউলিস্ট দেখাতে চাই । এখন আবার মেইন এক্টিভিটি তে ফিরে যান ।
public class MainActivity extends AppCompatActivity{
ListView listView;
int[] imageView = {R.drawable.SajibA, R.drawable.SajibB , R.drawable.SajibC,
R.drawable.SajibD , R.drawable.SajibE };
String[] location;
String[] year;
@Override
protected void Oncreate(Bundle savedInstanceState) {
super.onCreate(saveInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listView);
location = getResources().getStringArray(R.array.location);
year = getResources().getStringArray(R.array.year);
// এই পর্যন্ত কোড আগেই করা ছিল
int i=0;
for(String locations:location){
DataProvider dataProvider = new DataProvider(imageView[i],locations,year[i]);
i++;
// এটি ফরইচ লুপ । লুপের ভিতর ডাটা প্রোভাইডার এর একটি অব্জেক্ট তৈরি করে দিলাম ।এতে কন্সট্রাকটর হিসেবে ইমেজভিউ , লোকেশন ও আইডি পাস করলাম । ইমেজভিউ ও ইয়ারে i=0 দিয়ে ইনিশিয়ালাইজ করার মানে লুপের মাধ্যমে ৫টি অব্জেক্ট তৈরি করবে । আর লোকেশন এ প্রয়োজন হয় নাই কারন ফরইচ লুপ অনুযায়ী আপনি যে প্যারামিটার এই ফরইচ লুপ এর ভিতরে দিবেন সেটির সব ভ্যারিয়েবল গুলো একে একে চলে আসে । এখানে ফরইচ লুপের ভিতর আমরা লোকেশন দিয়ে দিয়েছি তাই লোকেশন এর সবগুলো অটোমেটিক চলে আসছে । আপনি চাইলে যে কোন একটি ব্যাবহার করতে পারেন ।
}
}
}
এখন আমাদের এডাপ্টর তৈরি করতে হবে । এর জন্য চাই আরো একটি জাভা ক্লাস । আগের জাভা ক্লাসের মাধ্যমে আমরা ডাটা গুলোকে একসাথে বেধে রেখেছি এবং যে কয়টি লিস্ট দরকার সেকয়টি অব্জেক্ট তৈরি করেছি আর এখন নতুন এক জাভা ক্লাসের মাধ্যমে সেই এক একটি বাধা বস্তা আমরা লেআউট এর ভিতরে নিয়ে যাবো । নতুন জাভা ক্লাসের নাম দিলাম DataAdapter
এখানে DataAdapter ক্লাসে extends করলাম ArrayAdapter , যেহেতু আমার ডাটাগুলো অ্যারে হয়ে আসতেছে । extends করার সময় ইরর দেখাবে তখন পাশের লাল বাল্ব এর উপর ক্লিক করলেই দেখবেন Create Constructor maching super দেখাছে , সেখানে ক্লিক করে প্রথম যে কন্সট্রাকর টি দেখাছে ২টি প্যারামিটার সহ সেটি ক্লিক করে ওকে প্রেস করুন ।
ডাটা প্রোভাইডার এর প্রত্যেক অব্জেক্ট Adapter এ সংযুক্ত করতে add ম্যাথড টি লিখে নিন । add লিখলেই দেখবেন চলে আসবে ।
এরপর এই অবজেক্টগুলো নিয়ে একটি লিস্ট তৈরি করার জন্য List ক্লাসের একটি অব্জেক্ট তৈরি করুন -
আমরা লিস্টের মাধ্যমেই পুরো ভিউটা ইন্টারফেস এ দেখাবো । এখন লিস্টে যে ডাটা আসবে সেটি কোথা থেকে আসবে ? ডাটা তো আছে ডাটা প্রোভাইডার এর মধ্যে । তাহলে আবার একটু মেইন এক্টিভিটি তে যেতে হবে । ডাটা প্রোভাইডার এর যে ৫টি অব্জেক্ট তৈরি করেছিলাম সেখান থেকে ডাটা নিয়ে আসতে হবে -
public class MainActivity extends AppCompatActivity{
ListView listView;
int[] imageView = {R.drawable.SajibA, R.drawable.SajibB , R.drawable.SajibC,
R.drawable.SajibD , R.drawable.SajibE };
String[] location;
String[] year;
DataAdapter adapter;
// DataAdapter ক্লাসের একটি অব্জেক্ট কল করলাম
@Override
protected void Oncreate(Bundle savedInstanceState) {
super.onCreate(saveInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listView);
location = getResources().getStringArray(R.array.location);
year = getResources().getStringArray(R.array.year);
adapter = new DataAdapter(this,R.layout.singlelistlayout);
listView.setAdapter(adapter);
// DataAdapter এর অব্জেক্ট তৈরি করলাম । মনে আছে কি DataAdapter ক্লাসে বাই ডিফল্ট একটা কন্সট্রাক্টর লিখতে হয়েছিল ২টি প্যারামিটার সহ । তো প্যারামিটার হিসেবে এখানে কনটেক্স ও যে লেআউট দেখাতে চাই সেটি পাস করতে হবে । যেহেতু এই এক্টিভিটি তেই আমরা লেআউট দেখাবো তাই কনটেক্স হিসেবে this কিংবা getBaseContext() কিংবা getApplicationContext() একটা লিখলেই হবে আর লেআউট এর নাম লিখে দিলাম । এই প্রোগ্রামে আমার একটিভিটি ক্লাস কিন্তু একটা জাভা ক্লাস ২ টা । জাভা ক্লাস ২টা কিন্তু একটিভিটি ক্লাস নাহ । এক্টিভিটি ক্লাস মানে যে ক্লাসের সাথে লেআউট থাকবে ।
// এর পরের লাইনে এই এক্টিভিটি ক্লাসে যে লিস্টভিউ অব্জেক্ট আছে সেটির সাথে এড করে দিলাম । কারন Adapter এর সাহায্যেই তো ডাটাগুলো এখানে এসে শো করবে । আর এই লাইন ২টি অবশ্যই ফরইচ লুপের উপরে হতে হবে ।
int i=0;
for(String locations:location){
DataProvider dataProvider = new DataProvider(imageView[i],locations,year[i]);
adapter.add(dataProvider);
// প্রতিবার DataProvider এর একটি অব্জেক্ট তৈরি হবে এবং সেই ডাটা adapter.add ম্যাথডের মাধ্যমে ডাটা এডাপ্টর ক্লাসে চলে যাবে ।
i++;
}
}
মেইন এক্টিভিটি তে আর কোন কাজ নেই । আবার DataAdapter ক্লাসে চলে আসুন -
উপরে add ম্যাথডের মধ্যে ডাটা পাস করেছি । তো DataAdapter এর এড ম্যাথডের ভিতর , DataAdapter এ তৈরি করা লিস্টের সাথে সংযুক্ত করতে লিখে দিন - এই ক্লাসের কোডটা হবে -
public class DataAdapter extends ArrayAdapter { List list = new ArrayList(); public DataAdapter(@NonNull Context context, int resource) { super(context, resource); } @Override public void add(@Nullable Object object) { super.add(object); list.add(object); }এখানে list.add এর মাধ্যমে সকল ডাটার একটি লিস্ট তৈরি করা হচ্ছে ।
এখন আরো একটি ম্যাথড এড করতে হবে -
সেটি হল ভিউ ম্যাথড । আমরা ডাটাও নিয়ে আসলাম , তার লিস্টও তৈরি করলাম কিন্তু কোন ডাটা কোন ভিউতে থাকবে সেটা সেট করে দিতে হবে । তো ডাটা কে কন্ট্রোল করতে এখানেই একটি স্ট্যাটিক ক্লাস তৈরি করি -
static class DataHandler{ ImageView image; TextView locations; TextView years;}
এখন ভিউ ম্যাথড টা লিখা যাক -
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
View row;
row = convertView;
DataHandler handler;
handler = new DataHandler();
LayoutInflater inflater =(LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row= inflater.inflate(R.layout.singlelistlayout,parent,false);
handler.image = (ImageView) row.findViewById(R.id.imageView);
handler.locations = (TextView) row.findViewById(R.id.location);
handler.years = (TextView) row.findViewById(R.id.year);
row.setTag(handler);
DataProvider dataProvider;
dataProvider = (DataProvider) this.getItem(position);
handler.image.setImageResource(dataProvider.getImageView());
handler.locations.setText(dataProvider.getLocation());
handler.years.setText(dataProvider.getYear());
return row;
}
ব্যাস , কাজ শেষ । এবার প্রজেক্টি রান করুন 😊😊😊
তাহলে আমাদের যে ফাইনাল ভিউটি দাঁড়ালো -
এখানে কোন ভিউতে ক্লিক করলে কিছু দেখাবে নাহ কারন তার কোন কোড আমরা লিখি নাই 😊
শেষ এ আরেকবার রিভিউ দিচ্ছি , আমাদের মোট ৩ টি ক্লাস এবং ২ টি xml ফাইল । প্রতি ক্লাসের কোডগুলো আবার দিয়ে দিচ্ছি -
strings.xml -
<resources>
<string name="app_name">Mashiur Rahman</string>
<string name="an_single_image">An single image</string>
<string name="mirpur">Mirpur</string>
<string name="_2016">2016</string>
<string-array name="location">
<item>Siddhersori</item>
<item>Dhaka</item>
<item>Mirpur</item>
<item>Barisal</item>
<item>Patuakhali</item>
</string-array>
<string-array name="year">
<item>2012</item>
<item>2013</item>
<item>2017</item>
<item>2016</item>
<item>2015</item>
</string-array>
</resources>
activity_main.xml -
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.user.mashiurrahman.MainActivity">
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</LinearLayout>
singlelistlayout.xml -
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="80dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="78dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/imageView"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:contentDescription="@string/an_single_image"/>
<TextView
android:id="@+id/location"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
/>
<TextView
android:id="@+id/year"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="@color/colorPrimary"></View>
</LinearLayout>
MainActivity.java -
package com.example.user.mashiurrahman;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
ListView listView;
int[] imageView = {R.drawable.bitcoin,R.drawable.facebook,R.drawable.google,R.drawable.images,R.drawable.unnamed};
String[] location;
String[] year;
DataAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listView);
location = getResources().getStringArray(R.array.location);
year = getResources().getStringArray(R.array.year);
int i = 0;
adapter = new DataAdapter(getBaseContext(), R.layout.singlelistlayout);
listView.setAdapter(adapter);
for(String locations : location) {
DataProvider dataProvider = new DataProvider(imageView[i], locations, year[i]);
adapter.add(dataProvider);
i++;
}
}
}
DataAdapter.java -
package com.example.user.mashiurrahman;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class DataAdapter extends ArrayAdapter {
List list = new ArrayList();
public DataAdapter(@NonNull Context context, int resource) {
super(context, resource);
}
@Override
public void add(@Nullable Object object) {
super.add(object);
list.add(object);
}
class DataHandler{
ImageView image;
TextView locations;
TextView years;
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
View row;
row = convertView;
DataHandler handler;
handler = new DataHandler();
LayoutInflater inflater =(LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row= inflater.inflate(R.layout.singlelistlayout,parent,false);
handler.image = (ImageView) row.findViewById(R.id.imageView);
handler.locations = (TextView) row.findViewById(R.id.location);
handler.years = (TextView) row.findViewById(R.id.year);
row.setTag(handler);
DataProvider dataProvider;
dataProvider = (DataProvider) this.getItem(position);
handler.image.setImageResource(dataProvider.getImageView());
handler.locations.setText(dataProvider.getLocation());
handler.years.setText(dataProvider.getYear());
return row;
}
}
DataProvider.java -
package com.example.user.mashiurrahman;
/**
* Created by User on 10/26/2017.
*/
public class DataProvider {
private int imageView;
private String location;
private String year;
public int getImageView() {
return imageView;
}
public DataProvider(int imageView, String location, String year) {
this.setImageView(imageView);
this.setLocation(location);
this.setYear(year);
}
public void setImageView(int imageView) {
this.imageView = imageView;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getYear() {
return year;
}
public void setYear(String year) {
this.year = year;
}
}
Thank You 😊😊😊😊😊😊😊😊😊😊😊😊😊😊
মন্তব্যসমূহ
একটি মন্তব্য পোস্ট করুন