১. ভূমিকা
ম্যাটেরিয়াল ডিজাইন হলো আকর্ষণীয় ও সুন্দর ডিজিটাল পণ্য তৈরির একটি পদ্ধতি। একগুচ্ছ সুসংহত নীতি ও উপাদানের অধীনে স্টাইল, ব্র্যান্ডিং, ইন্টারঅ্যাকশন এবং মোশনকে একত্রিত করার মাধ্যমে প্রোডাক্ট টিমগুলো তাদের ডিজাইনের সর্বোচ্চ সম্ভাবনাকে কাজে লাগাতে পারে।
ম্যাটেরিয়াল কম্পোনেন্টস (MDC) ডেভেলপারদের ম্যাটেরিয়াল ডিজাইন বাস্তবায়ন করতে সাহায্য করে। গুগলের একদল ইঞ্জিনিয়ার এবং ইউএক্স ডিজাইনার দ্বারা তৈরি, MDC-তে কয়েক ডজন সুন্দর এবং কার্যকরী UI কম্পোনেন্ট রয়েছে এবং এটি অ্যান্ড্রয়েড, আইওএস, ওয়েব এবং ফ্লাটারের জন্য উপলব্ধ। material.io/develop |
অ্যান্ড্রয়েডের জন্য ম্যাটেরিয়ালের মোশন সিস্টেমটি কী?
অ্যান্ড্রয়েডের জন্য ম্যাটেরিয়াল মোশন সিস্টেম হলো MDC-Android লাইব্রেরির অন্তর্গত একগুচ্ছ ট্রানজিশন প্যাটার্ন, যা ম্যাটেরিয়াল ডিজাইন নির্দেশিকায় বর্ণিত অনুযায়ী ব্যবহারকারীদের একটি অ্যাপ বুঝতে ও নেভিগেট করতে সাহায্য করে।
উপাদান রূপান্তরের চারটি প্রধান ধরণ নিম্নরূপ:
- কন্টেইনার ট্রান্সফর্ম: কন্টেইনারযুক্ত UI এলিমেন্টগুলোর মধ্যে ট্রানজিশন; একটি এলিমেন্টকে নির্বিঘ্নে অন্যটিতে রূপান্তরিত করার মাধ্যমে দুটি স্বতন্ত্র UI এলিমেন্টের মধ্যে একটি দৃশ্যমান সংযোগ তৈরি করে।
- শেয়ার্ড অ্যাক্সিস: এমন UI এলিমেন্টগুলোর মধ্যে ট্রানজিশন, যাদের মধ্যে একটি স্থানিক বা নেভিগেশনাল সম্পর্ক রয়েছে; এলিমেন্টগুলোর মধ্যকার সম্পর্ককে আরও দৃঢ় করতে x, y, বা z অ্যাক্সিসে একটি শেয়ার্ড ট্রান্সফরমেশন ব্যবহার করে।
- ফেড থ্রু: এমন UI এলিমেন্টগুলোর মধ্যে ট্রানজিশন বা রূপান্তর, যাদের একে অপরের সাথে কোনো দৃঢ় সম্পর্ক নেই; এটি একটি ক্রমিক ফেড আউট ও ফেড ইন পদ্ধতি ব্যবহার করে এবং আগত এলিমেন্টটিকে স্কেল করে।
- ফেড: স্ক্রিনের সীমানার মধ্যে UI এলিমেন্টগুলোর প্রবেশ বা প্রস্থানের জন্য ব্যবহৃত হয়।
MDC-Android লাইব্রেরিটি এই প্যাটার্নগুলির জন্য ট্রানজিশন ক্লাস প্রদান করে, যা AndroidX Transition লাইব্রেরি ( androidx.transition ) এবং Android Transition Framework ( android.transition ) উভয়ের উপর ভিত্তি করে নির্মিত:
অ্যান্ড্রয়েডএক্স
-
com.google.android.material.transitionপ্যাকেজে উপলব্ধ - এপিআই লেভেল ১৪+ সমর্থন করে
- ফ্র্যাগমেন্ট এবং ভিউ সমর্থন করে, কিন্তু অ্যাক্টিভিটি বা উইন্ডো সমর্থন করে না।
- এতে ব্যাকপোর্ট করা বাগ ফিক্স এবং এপিআই লেভেল জুড়ে সামঞ্জস্যপূর্ণ আচরণ রয়েছে।
কাঠামো
-
com.google.android.material.transition.platformপ্যাকেজে উপলব্ধ - এপিআই লেভেল ২১+ সমর্থন করে
- ফ্র্যাগমেন্ট, ভিউ, অ্যাক্টিভিটি এবং উইন্ডো সমর্থন করে।
- বাগ ফিক্সগুলো ব্যাকপোর্ট করা হয়নি এবং বিভিন্ন এপিআই লেভেলে এগুলোর আচরণ ভিন্ন হতে পারে।
এই কোডল্যাবে আপনারা AndroidX লাইব্রেরির উপর ভিত্তি করে নির্মিত ম্যাটেরিয়াল ট্রানজিশন ব্যবহার করবেন, অর্থাৎ আপনাদের মূল মনোযোগ থাকবে ফ্র্যাগমেন্ট এবং ভিউ-এর উপর।
আপনি যা তৈরি করবেন
এই কোডল্যাবটি আপনাকে কোটলিন ব্যবহার করে 'Reply ' নামক একটি উদাহরণ অ্যান্ড্রয়েড ইমেল অ্যাপে কিছু ট্রানজিশন তৈরি করতে নির্দেশনা দেবে, যা দেখাবে কীভাবে আপনি MDC-Android লাইব্রেরির ট্রানজিশন ব্যবহার করে আপনার অ্যাপের চেহারা ও অনুভূতি নিজের মতো করে সাজিয়ে নিতে পারেন।
Reply অ্যাপটির জন্য স্টার্টার কোড সরবরাহ করা হবে, এবং আপনাকে অ্যাপটিতে নিম্নলিখিত ম্যাটেরিয়াল ট্রানজিশনগুলো অন্তর্ভুক্ত করতে হবে, যা নিচে সম্পূর্ণ কোডল্যাবের GIF-টিতে দেখা যাচ্ছে:
- ইমেল তালিকা থেকে ইমেল বিস্তারিত পৃষ্ঠায় কন্টেইনার ট্রান্সফর্ম ট্রানজিশন
- FAB থেকে ইমেল কম্পোজ পেজে কন্টেইনার ট্রান্সফর্ম ট্রানজিশন
- সার্চ আইকন থেকে সার্চ ভিউ পেজে শেয়ার্ড জেড-অ্যাক্সিস ট্রানজিশন
- মেইলবক্স পৃষ্ঠাগুলির মধ্যে ধীরে ধীরে পরিবর্তন
- ইমেইল অ্যাড্রেস চিপ থেকে কার্ড ভিউতে কন্টেইনার ট্রান্সফর্ম ট্রানজিশন

আপনার যা যা লাগবে
- অ্যান্ড্রয়েড ডেভেলপমেন্ট এবং কোটলিন সম্পর্কে প্রাথমিক জ্ঞান
- অ্যান্ড্রয়েড স্টুডিও (আপনার কাছে না থাকলে এখান থেকে ডাউনলোড করুন)
- একটি অ্যান্ড্রয়েড এমুলেটর বা ডিভাইস (অ্যান্ড্রয়েড স্টুডিওর মাধ্যমে উপলব্ধ)
- নমুনা কোড (পরবর্তী ধাপ দেখুন)
অ্যান্ড্রয়েড অ্যাপ তৈরিতে আপনার অভিজ্ঞতার স্তরকে আপনি কীভাবে মূল্যায়ন করবেন?
২. আপনার ডেভেলপমেন্ট এনভায়রনমেন্ট সেট আপ করুন।
অ্যান্ড্রয়েড স্টুডিও চালু করুন
আপনি যখন অ্যান্ড্রয়েড স্টুডিও খুলবেন, তখন "Welcome to Android Studio" শিরোনামের একটি উইন্ডো প্রদর্শিত হবে। তবে, আপনি যদি প্রথমবারের মতো অ্যান্ড্রয়েড স্টুডিও চালু করে থাকেন, তাহলে ডিফল্ট মানগুলো ব্যবহার করে অ্যান্ড্রয়েড স্টুডিও সেটআপ উইজার্ডের ধাপগুলো অনুসরণ করুন। এই ধাপে প্রয়োজনীয় ফাইলগুলো ডাউনলোড এবং ইনস্টল হতে কয়েক মিনিট সময় লাগতে পারে, তাই পরবর্তী অংশের কাজ করার সময় এটিকে ব্যাকগ্রাউন্ডে চলতে দিতে পারেন।
বিকল্প ১: গিটহাব থেকে স্টার্টার কোডল্যাব অ্যাপটি ক্লোন করুন
গিটহাব থেকে এই কোডল্যাবটি ক্লোন করতে, নিম্নলিখিত কমান্ডগুলো চালান:
git clone https://github.com/material-components/material-components-android-motion-codelab.git cd material-components-android-motion-codelab
বিকল্প ২: স্টার্টার কোডল্যাব অ্যাপের জিপ ফাইলটি ডাউনলোড করুন।
স্টার্টার অ্যাপটি material-components-android-motion-codelab-develop ডিরেক্টরির মধ্যে অবস্থিত।
অ্যান্ড্রয়েড স্টুডিওতে স্টার্টার কোড লোড করুন।
- সেটআপ উইজার্ড শেষ হয়ে গেলে এবং 'Welcome to Android Studio' উইন্ডোটি দেখা গেলে, 'Open an existing Android Studio project'-এ ক্লিক করুন।

- যে ডিরেক্টরিতে আপনি নমুনা কোডটি ইনস্টল করেছিলেন সেখানে যান এবং প্রজেক্টটি খোলার জন্য নমুনা ডিরেক্টরিটি নির্বাচন করুন।
- অ্যান্ড্রয়েড স্টুডিও উইন্ডোর নিচের দিকে অ্যাক্টিভিটি ইন্ডিকেটরগুলোতে যেমনটা দেখানো হচ্ছে, প্রজেক্টটি বিল্ড ও সিঙ্ক হওয়ার জন্য কিছুক্ষণ অপেক্ষা করুন।
- এই পর্যায়ে, অ্যান্ড্রয়েড স্টুডিও কিছু বিল্ড এরর দেখাতে পারে, কারণ আপনার কাছে অ্যান্ড্রয়েড এসডিকে বা বিল্ড টুলস নেই, যেমনটি নিচে দেখানো হয়েছে। এগুলো ইনস্টল/আপডেট করতে এবং আপনার প্রজেক্ট সিঙ্ক করতে অ্যান্ড্রয়েড স্টুডিওর নির্দেশাবলী অনুসরণ করুন। এরপরও যদি আপনি সমস্যার সম্মুখীন হন, তবে এসডিকে ম্যানেজার ব্যবহার করে আপনার টুলস আপডেট করার গাইডটি অনুসরণ করুন।

প্রকল্পের নির্ভরতা যাচাই করুন
প্রজেক্টটির জন্য MDC-Android লাইব্রেরির উপর নির্ভরতা প্রয়োজন। আপনার ডাউনলোড করা স্যাম্পল কোডে এই নির্ভরতাটি আগে থেকেই তালিকাভুক্ত থাকার কথা, কিন্তু নিশ্চিত হওয়ার জন্য চলুন কনফিগারেশনটি দেখে নেওয়া যাক।
app মডিউলের build.gradle ফাইলে যান এবং নিশ্চিত করুন যে dependencies ব্লকে MDC-Android-এর উপর একটি ডিপেন্ডেন্সি অন্তর্ভুক্ত আছে:
implementation 'com.google.android.material:material:1.2.0'
স্টার্টার অ্যাপটি চালান
- ডিভাইস পছন্দের বাম দিকের বিল্ড কনফিগারেশনটি
appকিনা তা নিশ্চিত করুন। - অ্যাপটি বিল্ড ও রান করতে সবুজ রান / প্লে বাটনটি চাপুন।

- 'Select Deployment Target' উইন্ডোতে, আপনার উপলব্ধ ডিভাইসগুলোর তালিকায় যদি আগে থেকেই কোনো অ্যান্ড্রয়েড ডিভাইস তালিকাভুক্ত থাকে, তাহলে সরাসরি ধাপ ৮- এ চলে যান। অন্যথায়, 'Create New Virtual Device'-এ ক্লিক করুন।
- হার্ডওয়্যার নির্বাচন স্ক্রিনে, পিক্সেল ৩-এর মতো একটি ফোন ডিভাইস নির্বাচন করুন এবং তারপরে পরবর্তী (Next) ক্লিক করুন।
- সিস্টেম ইমেজ স্ক্রিনে, একটি সাম্প্রতিক অ্যান্ড্রয়েড সংস্করণ নির্বাচন করুন, বিশেষত সর্বোচ্চ এপিআই লেভেলেরটি। যদি এটি ইনস্টল করা না থাকে, তবে প্রদর্শিত ডাউনলোড লিঙ্কে ক্লিক করুন এবং ডাউনলোডটি সম্পূর্ণ করুন।
- পরবর্তী ধাপে যান।
- অ্যান্ড্রয়েড ভার্চুয়াল ডিভাইস (AVD) স্ক্রিনে, সেটিংস অপরিবর্তিত রেখে ফিনিশ-এ ক্লিক করুন।
- ডেপ্লয়মেন্ট টার্গেট ডায়ালগ থেকে একটি অ্যান্ড্রয়েড ডিভাইস নির্বাচন করুন।
- Ok ক্লিক করুন।
- অ্যান্ড্রয়েড স্টুডিও অ্যাপটি বিল্ড করে, ডেপ্লয় করে এবং টার্গেট ডিভাইসে স্বয়ংক্রিয়ভাবে খুলে দেয়।
সফল! Reply-এর হোম পেজের স্টার্টার কোডটি আপনার এমুলেটরে চালু হয়ে যাওয়ার কথা। আপনি ইনবক্সটি দেখতে পাবেন, যেখানে ইমেইলের একটি তালিকা থাকবে।

ঐচ্ছিক: ডিভাইসের অ্যানিমেশনগুলির গতি কমান
যেহেতু এই কোডল্যাবে দ্রুত অথচ নিখুঁত ট্রানজিশন রয়েছে, তাই এটি প্রয়োগ করার সময় ট্রানজিশনের কিছু সূক্ষ্ম বিবরণ পর্যবেক্ষণ করার জন্য ডিভাইসের অ্যানিমেশনগুলো ধীর করে নেওয়া সহায়ক হতে পারে। এটি adb শেল কমান্ড অথবা একটি কুইক সেটিংস টাইল (Quick Settings Tile) ব্যবহার করে করা যেতে পারে। মনে রাখবেন যে, ডিভাইসের অ্যানিমেশন ধীর করার এই পদ্ধতিগুলো রিপ্লাই (Reply) অ্যাপের বাইরের ডিভাইসের অ্যানিমেশনগুলোকেও প্রভাবিত করবে।
পদ্ধতি ১: এডিবি শেল কমান্ড
ডিভাইসের অ্যানিমেশনগুলোর গতি ১০ গুণ কমানোর জন্য, আপনি কমান্ড লাইন থেকে নিম্নলিখিত কমান্ডগুলো চালাতে পারেন:
adb shell settings put global window_animation_scale 10
adb shell settings put global transition_animation_scale 10
adb shell settings put global animator_duration_scale 10
ডিভাইসের অ্যানিমেশন গতি স্বাভাবিক অবস্থায় ফিরিয়ে আনতে, নিম্নলিখিত কমান্ডগুলো চালান:
adb shell settings put global window_animation_scale 1
adb shell settings put global transition_animation_scale 1
adb shell settings put global animator_duration_scale 1
পদ্ধতি ২: দ্রুত সেটিংস টাইল
বিকল্পভাবে, কুইক সেটিংস টাইল সেট আপ করার জন্য, প্রথমে আপনার ডিভাইসে ডেভেলপার সেটিংস চালু করুন, যদি আপনি আগে তা না করে থাকেন:
- ডিভাইসের "সেটিংস" অ্যাপটি খুলুন
- একদম নিচে স্ক্রোল করুন এবং 'About emulated device'-এ ক্লিক করুন।
- একদম নিচে স্ক্রল করুন এবং ডেভেলপার সেটিংস চালু না হওয়া পর্যন্ত দ্রুত 'বিল্ড নম্বর'-এ ক্লিক করতে থাকুন।
এরপরে, কুইক সেটিংস টাইলটি চালু করতে, ডিভাইসের 'সেটিংস' অ্যাপের মধ্যেই নিম্নলিখিত পদক্ষেপগুলি অনুসরণ করুন:
- স্ক্রিনের উপরের দিকে থাকা সার্চ আইকন বা সার্চ বারে ক্লিক করুন।
- সার্চ ফিল্ডে 'tiles' টাইপ করুন
- 'দ্রুত সেটিংস ডেভেলপার টাইলস' সারিতে ক্লিক করুন
- 'উইন্ডো অ্যানিমেশন স্কেল' সুইচটিতে ক্লিক করুন
অবশেষে, পুরো কোডল্যাব জুড়ে, স্ক্রিনের উপর থেকে সিস্টেম নোটিফিকেশন শেডটি নিচে টানুন এবং ব্যবহার করুন
ধীর এবং স্বাভাবিক গতির অ্যানিমেশনের মধ্যে পরিবর্তন করার জন্য আইকন।
৩. নমুনা অ্যাপ কোডটির সাথে পরিচিত হন।
চলুন কোডটি দেখে নেওয়া যাক। আমরা এমন একটি অ্যাপ দিয়েছি যা Jetpack Navigation কম্পোনেন্ট লাইব্রেরি ব্যবহার করে MainActivity নামক একটিমাত্র অ্যাক্টিভিটির মধ্যে কয়েকটি ভিন্ন Fragment-এর মধ্যে নেভিগেট করে।
- HomeFragment: ইমেইলের তালিকা প্রদর্শন করে
- EmailFragment: একটি একক, সম্পূর্ণ ইমেল প্রদর্শন করে
- ComposeFragment: এর মাধ্যমে একটি নতুন ইমেল রচনা করা যায়।
- SearchFragment: একটি সার্চ ভিউ প্রদর্শন করে
নেভিগেশন_গ্রাফ.এক্সএমএল
প্রথমে, অ্যাপের নেভিগেশন গ্রাফ কীভাবে সেট আপ করা হয়েছে তা বোঝার জন্য, app -> src -> main -> res -> navigation ডিরেক্টরিতে থাকা navigation_graph.xml খুলুন:
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/navigation_graph"
app:startDestination="@id/homeFragment">
<fragment
android:id="@+id/homeFragment"
android:name="com.materialstudies.reply.ui.home.HomeFragment"
android:label="HomeFragment">
<argument...>
<action
android:id="@+id/action_homeFragment_to_emailFragment"
app:destination="@id/emailFragment" />
</fragment>
<fragment
android:id="@+id/emailFragment"
android:name="com.materialstudies.reply.ui.email.EmailFragment"
android:label="EmailFragment">
<argument...>
</fragment>
<fragment
android:id="@+id/composeFragment"
android:name="com.materialstudies.reply.ui.compose.ComposeFragment"
android:label="ComposeFragment">
<argument...>
</fragment>
<fragment
android:id="@+id/searchFragment"
android:name="com.materialstudies.reply.ui.search.SearchFragment"
android:label="SearchFragment" />
<action
android:id="@+id/action_global_homeFragment"
app:destination="@+id/homeFragment"
app:launchSingleTop="true"
app:popUpTo="@+id/navigation_graph"
app:popUpToInclusive="true"/>
<action
android:id="@+id/action_global_composeFragment"
app:destination="@+id/composeFragment" />
<action
android:id="@+id/action_global_searchFragment"
app:destination="@+id/searchFragment" />
</navigation>
লক্ষ্য করুন, উপরে উল্লিখিত সমস্ত ফ্র্যাগমেন্ট কীভাবে উপস্থিত রয়েছে, যেখানে ডিফল্ট লঞ্চ ফ্র্যাগমেন্টটি app:startDestination="@id/homeFragment" এর মাধ্যমে ` HomeFragment এ সেট করা আছে। ফ্র্যাগমেন্ট ডেস্টিনেশন গ্রাফের এই XML সংজ্ঞা, এবং সেইসাথে অ্যাকশনগুলো, জেনারেটেড কোটলিন নেভিগেশন কোডকে তথ্য সরবরাহ করে, যা আপনি ট্রানজিশন সংযুক্ত করার সময় দেখতে পাবেন।
activity_main.xml
এরপরে, app -> src -> main -> res -> layout ডিরেক্টরিতে থাকা activity_main.xml লেআউটটি দেখুন। আপনি NavHostFragment টি দেখতে পাবেন, যেটি উপরের নেভিগেশন গ্রাফ দিয়ে কনফিগার করা আছে:
<fragment
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/navigation_graph"/>
এই NavHostFragment স্ক্রিন জুড়ে থাকে এবং অ্যাপের সমস্ত ফুল স্ক্রিন ফ্র্যাগমেন্ট নেভিগেশন পরিবর্তন পরিচালনা করে। activity_main.xml এ থাকা BottomAppBar এবং এর অ্যাঙ্কর করা FloatingActionButton , NavHostFragment দ্বারা প্রদর্শিত বর্তমান ফ্র্যাগমেন্টের উপরে বিন্যস্ত থাকে, এবং তাই প্রদত্ত স্যাম্পল অ্যাপ কোড অনুযায়ী ফ্র্যাগমেন্টের গন্তব্যের উপর নির্ভর করে এগুলো দেখানো বা লুকানো হবে।
এছাড়াও, activity_main.xml এ থাকা BottomNavDrawerFragment হলো একটি বটম ড্রয়ার, যার মধ্যে বিভিন্ন ইমেল মেইলবক্সের মধ্যে নেভিগেট করার জন্য একটি মেনু থাকে, যা BottomAppBar Reply লোগো বাটনের মাধ্যমে শর্তসাপেক্ষে দেখানো হয়।
MainActivity.kt
সবশেষে, নেভিগেশন অ্যাকশনের একটি উদাহরণ দেখতে, app -> src -> main -> java -> com.materialstudies.reply.ui ডিরেক্টরিতে থাকা MainActivity.kt খুলুন। navigateToSearch() ফাংশনটি খুঁজুন, যা দেখতে এইরকম হবে:
private fun navigateToSearch() {
val directions = SearchFragmentDirections.actionGlobalSearchFragment()
findNavController(R.id.nav_host_fragment).navigate(directions)
}
এখানে দেখানো হয়েছে, কীভাবে কোনো কাস্টম ট্রানজিশন ছাড়াই সার্চ ভিউ পেজে নেভিগেট করা যায়। এই কোডল্যাবে, আপনি Reply-এর MainActivity এবং চারটি প্রধান ফ্র্যাগমেন্টে গভীরভাবে কাজ করে ম্যাটেরিয়াল ট্রানজিশন সেট আপ করবেন, যা অ্যাপ জুড়ে বিভিন্ন নেভিগেশন অ্যাকশনের সাথে একযোগে কাজ করে।
এখন যেহেতু আপনি স্টার্টার কোডের সাথে পরিচিত হয়েছেন, চলুন আমাদের প্রথম ট্রানজিশনটি বাস্তবায়ন করি।
৪. ইমেল তালিকা থেকে ইমেল বিস্তারিত পৃষ্ঠায় কন্টেইনার ট্রান্সফর্ম ট্রানজিশন যোগ করুন।
শুরুতে, আপনি একটি ইমেইলে ক্লিক করার সময় একটি ট্রানজিশন যোগ করবেন। এই নেভিগেশন পরিবর্তনের জন্য কন্টেইনার ট্রান্সফর্ম প্যাটার্নটি বেশ উপযুক্ত, কারণ এটি কন্টেইনারযুক্ত UI এলিমেন্টগুলোর মধ্যে ট্রানজিশনের জন্য ডিজাইন করা হয়েছে। এই প্যাটার্নটি দুটি UI এলিমেন্টের মধ্যে একটি দৃশ্যমান সংযোগ তৈরি করে।
কোনো কোড যোগ করার আগে, রিপ্লাই অ্যাপটি চালিয়ে একটি ইমেইলে ক্লিক করে দেখুন। এতে একটি সাধারণ জাম্প-কাট হওয়া উচিত, যার অর্থ হলো কোনো ট্রানজিশন ছাড়াই স্ক্রিনটি প্রতিস্থাপিত হয়ে যাবে।

নিচের কোড স্নিপেটে দেখানো অনুযায়ী, email_item_layout.xml ফাইলের MaterialCardView তে একটি transitionName অ্যাট্রিবিউট যোগ করে শুরু করুন:
ইমেল_আইটেম_লেআউট.xml
android:transitionName="@{@string/email_card_transition_name(email.id)}"
ট্রানজিশন নামটি একটি প্যারামিটারসহ একটি স্ট্রিং রিসোর্স গ্রহণ করে। আমাদের EmailFragment এর প্রতিটি transitionName যেন অনন্য হয়, তা নিশ্চিত করতে আপনাকে প্রতিটি ইমেইলের আইডি ব্যবহার করতে হবে।
এখন যেহেতু আপনার ইমেল তালিকা আইটেমের ট্রানজিশন নামটি সেট করা হয়ে গেছে, চলুন ইমেল বিবরণ লেআউটেও একই কাজ করি। fragment_email.xml এ, MaterialCardView এর transitionName কে নিম্নলিখিত স্ট্রিং রিসোর্সটিতে সেট করুন:
fragment_email.xml
android:transitionName="@string/email_card_detail_transition_name"
HomeFragment.kt এর onEmailClicked এর ভেতরের কোডটি নিচের কোড স্নিপেট দিয়ে প্রতিস্থাপন করুন, যাতে আপনার স্টার্ট ভিউ (ইমেল লিস্ট আইটেম) এবং এন্ড ভিউ (ইমেল ডিটেইলস স্ক্রিন)-এর মধ্যে ম্যাপিং তৈরি হয়:
HomeFragment.kt
val emailCardDetailTransitionName = getString(R.string.email_card_detail_transition_name)
val extras = FragmentNavigatorExtras(cardView to emailCardDetailTransitionName)
val directions = HomeFragmentDirections.actionHomeFragmentToEmailFragment(email.id)
findNavController().navigate(directions, extras)
এখন যেহেতু আপনি প্রাথমিক কাঠামো কনফিগার করে ফেলেছেন, আপনি একটি কন্টেইনার ট্রান্সফর্ম তৈরি করতে পারেন। EmailFragment onCreate মেথডে, নিম্নলিখিত কোড স্নিপেটটি যোগ করে sharedElementEnterTransition একটি MaterialContainerTransform এর নতুন ইনস্ট্যান্সে সেট করুন ( com.google.android.material.transition ভার্সনের পরিবর্তে com.google.android.material.transition.platform ভার্সনটি ইম্পোর্ট করে):
EmailFragment.kt
sharedElementEnterTransition = MaterialContainerTransform().apply {
drawingViewId = R.id.nav_host_fragment
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
scrimColor = Color.TRANSPARENT
setAllContainerColors(requireContext().themeColor(R.attr.colorSurface))
}
এখন অ্যাপটি পুনরায় চালানোর চেষ্টা করুন।

সবকিছু বেশ ভালো দেখাচ্ছে! আপনি যখন ইমেল তালিকার কোনো ইমেলে ক্লিক করবেন, তখন একটি কন্টেইনার ট্রান্সফর্মের মাধ্যমে তালিকার আইটেমটি প্রসারিত হয়ে একটি পূর্ণ স্ক্রিনের বিস্তারিত পৃষ্ঠায় পরিণত হওয়ার কথা। তবে, লক্ষ্য করুন, ব্যাক বাটন চাপলেও ইমেলটি আবার তালিকার মধ্যে সংকুচিত হয়ে যাচ্ছে না। এছাড়াও, ট্রানজিশন শুরু হওয়ার সাথে সাথেই ইমেল তালিকাটি অদৃশ্য হয়ে যাচ্ছে এবং ধূসর উইন্ডো ব্যাকগ্রাউন্ডটি দেখা যাচ্ছে। সুতরাং, আমাদের কাজ এখনো শেষ হয়নি।
রিটার্ন ট্রানজিশন ঠিক করতে, HomeFragment.kt এর onViewCreated মেথডে নিম্নলিখিত দুটি লাইন যোগ করুন:
HomeFragment.kt
postponeEnterTransition()
view.doOnPreDraw { startPostponedEnterTransition() }
অ্যাপটি আবার চালু করে দেখুন। ইমেল খোলার পর ব্যাক বাটন চাপলে ইমেলটি আবার তালিকার মধ্যে সংকুচিত হয়ে যাবে। চমৎকার! চলুন অ্যানিমেশনটি আরও উন্নত করি।
ইমেল তালিকাটি অদৃশ্য হয়ে যাওয়ার কারণ হলো, নেভিগেশন কম্পোনেন্ট ব্যবহার করে একটি নতুন ফ্র্যাগমেন্টে যাওয়ার সময় বর্তমান ফ্র্যাগমেন্টটি সঙ্গে সঙ্গে মুছে গিয়ে আমাদের নতুন আগত ফ্র্যাগমেন্ট দ্বারা প্রতিস্থাপিত হয়। প্রতিস্থাপিত হওয়ার পরেও ইমেল তালিকাটি দৃশ্যমান রাখতে, আপনি HomeFragment এ একটি এক্সিট ট্রানজিশন যোগ করতে পারেন।
HomeFragment onEmailClicked মেথডে নিচের কোডটুকু যোগ করুন, যাতে প্রোগ্রাম থেকে বের হওয়ার সময় ইমেলের তালিকাটি ধীরে ধীরে ছোট হয়ে যায় এবং পুনরায় প্রবেশের সময় আবার ছোট হয়ে আসে:
HomeFragment.kt
exitTransition = MaterialElevationScale(false).apply {
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
reenterTransition = MaterialElevationScale(true).apply {
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
এরপরে, হায়ারার্কির প্রতিটি স্বতন্ত্র ভিউতে প্রয়োগ না হয়ে, MaterialElevationScale ট্রানজিশনটি যেন পুরো হোম স্ক্রিনে প্রয়োগ হয় তা নিশ্চিত করতে, fragment_home.xml এ থাকা RecyclerView কে একটি ট্রানজিশন গ্রুপ হিসেবে চিহ্নিত করুন।
fragment_home.xml
android:transitionGroup="true"
এই পর্যায়ে, আপনার একটি সম্পূর্ণ কার্যকর কন্টেইনার ট্রান্সফর্ম থাকা উচিত। কোনো ইমেইলে ক্লিক করলে লিস্ট আইটেমটি প্রসারিত হয়ে একটি ডিটেইলস স্ক্রিন তৈরি করে এবং ইমেইলের তালিকাটি সংকুচিত হয়ে যায়। ব্যাক বাটন চাপলে ইমেইলের ডিটেইলস স্ক্রিনটি আবার সংকুচিত হয়ে লিস্ট আইটেমে পরিণত হয় এবং ইমেইলের তালিকাটি বড় হতে থাকে।

৫. FAB থেকে ইমেল কম্পোজ পেজে কন্টেইনার ট্রান্সফর্ম ট্রানজিশন যোগ করুন।
চলুন কন্টেইনার ট্রান্সফর্ম নিয়ে কাজ চালিয়ে যাই এবং ফ্লোটিং অ্যাকশন বাটন থেকে ComposeFragment -এ একটি ট্রানজিশন যোগ করি, যা FAB-টিকে প্রসারিত করে ব্যবহারকারীর লেখার জন্য একটি নতুন ইমেইলে নিয়ে যাবে। প্রথমে, অ্যাপটি পুনরায় রান করুন এবং FAB-টিতে ক্লিক করে দেখুন যে ইমেইল কম্পোজ স্ক্রিনটি চালু হওয়ার সময় কোনো ট্রানজিশন হচ্ছে না।

যদিও আমরা একই ট্রানজিশন ক্লাস ব্যবহার করি, এই ইনস্ট্যান্সটি কনফিগার করার পদ্ধতি ভিন্ন হবে, কারণ আমাদের FAB-টি MainActivity তে থাকে এবং আমাদের ComposeFragment MainActivity র নেভিগেশন হোস্ট কন্টেইনারের ভিতরে রাখা হয়।
ComposeFragment.kt ফাইলের onViewCreated মেথডে নিম্নলিখিত কোডটুকু যোগ করুন এবং অবশ্যই Slide এর androidx.transition ভার্সনটি ইম্পোর্ট করবেন।
ComposeFragment.kt
enterTransition = MaterialContainerTransform().apply {
startView = requireActivity().findViewById(R.id.fab)
endView = emailCardView
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
scrimColor = Color.TRANSPARENT
containerColor = requireContext().themeColor(R.attr.colorSurface)
startContainerColor = requireContext().themeColor(R.attr.colorSecondary)
endContainerColor = requireContext().themeColor(R.attr.colorSurface)
}
returnTransition = Slide().apply {
duration = resources.getInteger(R.integer.reply_motion_duration_medium).toLong()
addTarget(R.id.email_card_view)
}
আমাদের পূর্ববর্তী কন্টেইনার ট্রান্সফর্ম কনফিগার করতে ব্যবহৃত প্যারামিটারগুলোর পাশাপাশি, এখানে startView এবং endView ম্যানুয়ালি সেট করা হচ্ছে। কোন ভিউগুলো ট্রান্সফর্ম করা উচিত তা অ্যান্ড্রয়েড ট্রানজিশন সিস্টেমকে জানানোর জন্য transitionName অ্যাট্রিবিউট ব্যবহার করার পরিবর্তে, প্রয়োজনে আপনি এগুলো ম্যানুয়ালি নির্দিষ্ট করতে পারেন।
এখন, অ্যাপটি আবার চালান। আপনি দেখবেন FAB-টি কম্পোজ স্ক্রিনে রূপান্তরিত হচ্ছে (এই ধাপের শেষে থাকা GIF-টি দেখুন)।
আগের ধাপের মতোই, HomeFragment ComposeFragment দ্বারা সরিয়ে ও প্রতিস্থাপন করার পরেও যাতে এটি অদৃশ্য না হয়ে যায়, সেজন্য আপনাকে এতে একটি ট্রানজিশন যোগ করতে হবে।
MainActivity এর navigateToCompose মেথডে NavController navigate কল করার আগে নিচের কোডটুকু কপি করুন।
MainActivity.kt
currentNavigationFragment?.apply {
exitTransition = MaterialElevationScale(false).apply {
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
reenterTransition = MaterialElevationScale(true).apply {
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
}
এই ধাপের জন্য এটুকুই! FAB থেকে কম্পোজ স্ক্রিনে আপনার একটি ট্রানজিশন থাকা উচিত যা দেখতে নিচের ছবির মতো হবে:

৬. সার্চ আইকন থেকে সার্চ ভিউ পেজে শেয়ার্ড জেড-অ্যাক্সিস ট্রানজিশন যোগ করুন
এই ধাপে, আমরা সার্চ আইকন থেকে ফুল স্ক্রিন সার্চ ভিউতে একটি ট্রানজিশন যোগ করব। যেহেতু এই নেভিগেশন পরিবর্তনে কোনো স্থায়ী কন্টেইনার জড়িত নেই, তাই আমরা দুটি স্ক্রিনের মধ্যে স্থানিক সম্পর্ককে আরও জোরদার করতে এবং অ্যাপের হায়ারার্কিতে এক ধাপ উপরে যাওয়ার ইঙ্গিত দিতে একটি শেয়ার্ড জেড-অ্যাক্সিস ট্রানজিশন ব্যবহার করতে পারি।
অতিরিক্ত কোনো কোড যোগ করার আগে, অ্যাপটি রান করে স্ক্রিনের নিচের ডান কোণায় থাকা সার্চ আইকনটিতে ট্যাপ করুন। এতে কোনো ট্রানজিশন ছাড়াই সার্চ ভিউ স্ক্রিনটি চলে আসবে।

শুরু করার জন্য, MainActivity তে navigateToSearch মেথডটি খুঁজুন এবং বর্তমান ফ্র্যাগমেন্টের প্রস্থান ও MaterialSharedAxis Z-Axis-এ পুনরায় প্রবেশের ট্রানজিশন সেট আপ করতে NavController navigate মেথড কলের আগে নিম্নলিখিত কোড স্নিপেটটি যোগ করুন।
MainActivity.kt
currentNavigationFragment?.apply {
exitTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true).apply {
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false).apply {
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
}
এরপরে, SearchFragment এর onCreate মেথডে নিম্নলিখিত কোড স্নিপেটটি যোগ করুন, যা এর enter এবং return MaterialSharedAxis ট্রানজিশনগুলো কনফিগার করে।
SearchFragment.kt
enterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true).apply {
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
returnTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false).apply {
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
সবশেষে, হায়ারার্কির প্রতিটি স্বতন্ত্র ভিউতে প্রয়োগ না হয়ে, MaterialSharedAxis ট্রানজিশনটি যেন পুরো সার্চ স্ক্রিনে প্রয়োগ হয় তা নিশ্চিত করতে, fragment_search.xml এ থাকা LinearLayout কে একটি ট্রানজিশন গ্রুপ হিসেবে চিহ্নিত করুন।
fragment_search.xml
android:transitionGroup="true"
ব্যাস! এবার অ্যাপটি আবার চালু করে সার্চ আইকনে ট্যাপ করুন। হোম এবং সার্চ ভিউ স্ক্রিন দুটি একই সাথে Z-অক্ষ বরাবর গভীরতায় ফেড ও স্কেল হতে থাকবে, যা স্ক্রিন দুটির মধ্যে একটি নির্বিঘ্ন প্রভাব তৈরি করবে।

৭. মেইলবক্স পেজগুলোর মধ্যে ফেড থ্রু ট্রানজিশন যোগ করুন।
এই ধাপে, আমরা বিভিন্ন মেইলবক্সের মধ্যে একটি ট্রানজিশন যোগ করব। যেহেতু আমরা কোনো স্থানিক বা শ্রেণিবিন্যাসগত সম্পর্কের ওপর জোর দিতে চাই না, তাই ইমেইলের তালিকাগুলোর মধ্যে একটি সাধারণ 'অদলবদল' করার জন্য আমরা ফেড-থ্রু ব্যবহার করব।
অতিরিক্ত কোনো কোড যোগ করার আগে, অ্যাপটি চালিয়ে দেখুন, বটম অ্যাপ বারে থাকা রিপ্লাই লোগোতে ট্যাপ করুন এবং মেইলবক্স পরিবর্তন করুন। ইমেইলের তালিকাটি কোনো ট্রানজিশন ছাড়াই পরিবর্তিত হওয়া উচিত।

শুরু করার জন্য, MainActivity তে navigateToHome মেথডটি খুঁজুন এবং বর্তমান ফ্র্যাগমেন্টের এক্সিট MaterialFadeThrough ট্রানজিশন সেট আপ করতে NavController navigate মেথড কলের আগে নিম্নলিখিত কোড স্নিপেটটি যোগ করুন।
MainActivity.kt
currentNavigationFragment?.apply {
exitTransition = MaterialFadeThrough().apply {
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
}
এরপর, HomeFragment খুলুন। onCreate এর মধ্যে, fragment-টির enterTransition MaterialFadeThrough এর একটি নতুন ইনস্ট্যান্সে সেট করুন।
HomeFragment.kt
enterTransition = MaterialFadeThrough().apply {
duration = resources.getInteger(R.integer.reply_motion_duration_large).toLong()
}
অ্যাপটি আবার চালান। যখন আপনি নিচের নেভিগেশন ড্রয়ারটি খুলবেন এবং মেইলবক্স পরিবর্তন করবেন, তখন ইমেইলের বর্তমান তালিকাটি ধীরে ধীরে অদৃশ্য হয়ে যাবে এবং নতুন তালিকাটি ধীরে ধীরে দৃশ্যমান হবে। চমৎকার!

৮. ইমেল অ্যাড্রেস চিপ থেকে কার্ড ভিউতে কন্টেইনার ট্রান্সফর্ম ট্রানজিশন যোগ করুন।
এই ধাপে, আপনি একটি ট্রানজিশন যোগ করবেন যা একটি চিপকে পপআপ কার্ডে রূপান্তরিত করবে। এখানে একটি কন্টেইনার ট্রান্সফর্ম ব্যবহার করা হয়েছে ব্যবহারকারীকে এটা বোঝাতে যে, পপআপের ভেতরের কাজটি সেই চিপটিকেও প্রভাবিত করবে যেখান থেকে পপআপটি তৈরি হয়েছে।
কোনো কোড যোগ করার আগে, রিপ্লাই অ্যাপটি চালান, একটি ইমেইলে ক্লিক করুন, "রিপ্লাই" FAB-এ ক্লিক করুন এবং তারপর প্রাপকের কন্ট্যাক্ট চিপটিতে ক্লিক করার চেষ্টা করুন। চিপটি সঙ্গে সঙ্গে অদৃশ্য হয়ে যাবে এবং কোনো অ্যানিমেশন ছাড়াই সেই কন্ট্যাক্টের ইমেইল অ্যাড্রেসসহ একটি কার্ড ভেসে উঠবে।

এই ধাপে আপনি ComposeFragment এ কাজ করবেন। ComposeFragment লেআউটে আগে থেকেই প্রাপকের চিপস (যা ডিফল্টরূপে দৃশ্যমান) এবং একটি প্রাপকের কার্ড (যা ডিফল্টরূপে অদৃশ্য) যোগ করা আছে। এই প্রাপকের চিপ এবং এই কার্ড হলো সেই দুটি ভিউ, যাদের মধ্যে আপনি একটি কন্টেইনার ট্রান্সফর্ম তৈরি করবেন।
শুরু করার জন্য, ComposeFragment খুলুন এবং expandChip মেথডটি খুঁজুন। প্রদত্ত chip ক্লিক করা হলে এই মেথডটি কল করা হয়। recipientCardView এবং chip ভিজিবিলিটি অদলবদল করে এমন লাইনগুলোর উপরে নিম্নলিখিত কোড স্নিপেটটি যোগ করুন, যা beginDelayedTransition মাধ্যমে রেজিস্টার করা কন্টেইনার ট্রান্সফর্মটিকে ট্রিগার করবে।
ComposeFragment.kt
val transform = MaterialContainerTransform().apply {
startView = chip
endView = binding.recipientCardView
scrimColor = Color.TRANSPARENT
endElevation = requireContext().resources.getDimension(
R.dimen.email_recipient_card_popup_elevation_compat
)
addTarget(binding.recipientCardView)
}
TransitionManager.beginDelayedTransition(binding.composeConstraintLayout, transform)
আপনি এখন অ্যাপটি চালালে, চিপটি প্রাপকের জন্য ইমেল ঠিকানার একটি কার্ডে রূপান্তরিত হবে। এরপর, কার্ডটিকে আবার চিপে পরিণত করার জন্য রিটার্ন ট্রানজিশনটি কনফিগার করা যাক।
ComposeFragment এর collapseChip মেথডে, কার্ডটিকে আবার চিপের মধ্যে গুটিয়ে ফেলার জন্য নিচের কোড স্নিপেটটি যোগ করুন।
ComposeFragment.kt
val transform = MaterialContainerTransform().apply {
startView = binding.recipientCardView
endView = chip
scrimColor = Color.TRANSPARENT
startElevation = requireContext().resources.getDimension(
R.dimen.email_recipient_card_popup_elevation_compat
)
addTarget(chip)
}
TransitionManager.beginDelayedTransition(binding.composeConstraintLayout, transform)
অ্যাপটি আবার চালান। চিপটিতে ক্লিক করলে সেটি একটি কার্ডে পরিণত হবে এবং কার্ডটিতে ক্লিক করলে তা আবার চিপের মধ্যে সংকুচিত হয়ে যাবে। চমৎকার!

৯. সব শেষ।
১০০ লাইনেরও কম কোটলিন কোড এবং কিছু সাধারণ এক্সএমএল মার্কআপ ব্যবহার করে, এমডিসি-অ্যান্ড্রয়েড লাইব্রেরিটি আপনাকে একটি বিদ্যমান অ্যাপে সুন্দর ট্রানজিশন তৈরি করতে সাহায্য করেছে, যা ম্যাটেরিয়াল ডিজাইন নির্দেশিকা মেনে চলে এবং সমস্ত অ্যান্ড্রয়েড ডিভাইসে দেখতে ও আচরণে সামঞ্জস্যপূর্ণ থাকে।

পরবর্তী পদক্ষেপ
ম্যাটেরিয়াল মোশন সিস্টেম সম্পর্কে আরও তথ্যের জন্য, স্পেক এবং সম্পূর্ণ ডেভেলপার ডকুমেন্টেশন দেখে নিন, এবং আপনার অ্যাপে কিছু ম্যাটেরিয়াল ট্রানজিশন যোগ করার চেষ্টা করুন!
ম্যাটেরিয়াল মোশন ব্যবহার করার জন্য ধন্যবাদ। আমরা আশা করি আপনি এই কোডল্যাবটি উপভোগ করেছেন!