1. ভূমিকা
ম্যাটেরিয়াল ডিজাইন হলো সাহসী এবং সুন্দর ডিজিটাল পণ্য তৈরির একটি ব্যবস্থা। নীতি এবং উপাদানগুলির একটি সুসংগত সেটের অধীনে স্টাইল, ব্র্যান্ডিং, মিথস্ক্রিয়া এবং গতিকে একত্রিত করে, পণ্য দলগুলি তাদের সর্বাধিক নকশা সম্ভাবনা উপলব্ধি করতে পারে।
| ম্যাটেরিয়াল কম্পোনেন্টস (MDC) ডেভেলপারদের ম্যাটেরিয়াল ডিজাইন বাস্তবায়নে সাহায্য করে। গুগলের ইঞ্জিনিয়ার এবং UX ডিজাইনারদের একটি দল দ্বারা তৈরি, MDC-তে কয়েক ডজন সুন্দর এবং কার্যকরী UI উপাদান রয়েছে এবং এটি অ্যান্ড্রয়েড, iOS, ওয়েব এবং Flutter.material.io/develop-এর জন্য উপলব্ধ। |
ফ্লটারের জন্য ম্যাটেরিয়ালের গতি ব্যবস্থা কী?
ফ্লটারের জন্য ম্যাটেরিয়াল মোশন সিস্টেম হল অ্যানিমেশন প্যাকেজের মধ্যে ট্রানজিশন প্যাটার্নের একটি সেট যা ব্যবহারকারীদের ম্যাটেরিয়াল ডিজাইন নির্দেশিকাতে বর্ণিত একটি অ্যাপ বুঝতে এবং নেভিগেট করতে সাহায্য করতে পারে।
চারটি প্রধান উপাদান পরিবর্তনের ধরণ নিম্নরূপ:
- কন্টেইনার ট্রান্সফর্ম: একটি কন্টেইনার সহ UI উপাদানের মধ্যে রূপান্তর; একটি উপাদানকে অন্যটিতে নির্বিঘ্নে রূপান্তর করে দুটি স্বতন্ত্র UI উপাদানের মধ্যে একটি দৃশ্যমান সংযোগ তৈরি করে।

- ভাগ করা অক্ষ: স্থানিক বা নেভিগেশনাল সম্পর্কযুক্ত UI উপাদানগুলির মধ্যে রূপান্তর; উপাদানগুলির মধ্যে সম্পর্ককে শক্তিশালী করতে x, y, অথবা z অক্ষের উপর একটি ভাগ করা রূপান্তর ব্যবহার করে।

- ফেড থ্রু: যেসব UI উপাদানের সাথে একে অপরের দৃঢ় সম্পর্ক নেই তাদের মধ্যে ট্রানজিশন; ইনকামিং এলিমেন্টের স্কেল সহ একটি ক্রমিক ফেড আউট এবং ফেড ইন ব্যবহার করে।

- ফেইড: স্ক্রিনের সীমানার মধ্যে প্রবেশ করে বা প্রস্থান করে এমন UI উপাদানগুলির জন্য ব্যবহৃত হয়।

অ্যানিমেশন প্যাকেজটি এই প্যাটার্নগুলির জন্য ট্রানজিশন উইজেট অফার করে, যা ফ্লটার অ্যানিমেশন লাইব্রেরি ( flutter/animation.dart ) এবং ফ্লটার ম্যাটেরিয়াল লাইব্রেরি ( flutter/material.dart ) উভয়ের উপরে তৈরি করা হয়েছে:
এই কোডল্যাবে আপনি ফ্লাটার ফ্রেমওয়ার্ক এবং ম্যাটেরিয়াল লাইব্রেরির উপরে নির্মিত ম্যাটেরিয়াল ট্রানজিশন ব্যবহার করবেন, যার অর্থ আপনি উইজেটগুলি নিয়ে কাজ করবেন। :)
তুমি কী তৈরি করবে
এই কোডল্যাবটি আপনাকে ডার্ট ব্যবহার করে রিপ্লাই নামক একটি উদাহরণ ফ্লাটার ইমেল অ্যাপে কিছু ট্রানজিশন তৈরি করার ক্ষেত্রে নির্দেশনা দেবে, যাতে আপনি আপনার অ্যাপের চেহারা এবং অনুভূতি কাস্টমাইজ করার জন্য অ্যানিমেশন প্যাকেজ থেকে ট্রানজিশন কীভাবে ব্যবহার করতে পারেন তা প্রদর্শন করতে পারেন।
রিপ্লাই অ্যাপের জন্য স্টার্টার কোড প্রদান করা হবে, এবং আপনি অ্যাপটিতে নিম্নলিখিত উপাদান রূপান্তরগুলি অন্তর্ভুক্ত করবেন, যা নীচে সম্পূর্ণ কোডল্যাবের GIF তে দেখা যাবে:
- কন্টেইনার ইমেল তালিকা থেকে ইমেল বিস্তারিত পৃষ্ঠায় রূপান্তর রূপান্তর
- FAB থেকে কম্পোজ ইমেল পৃষ্ঠায় কনটেইনার ট্রান্সফর্ম রূপান্তর
- সার্চ আইকন থেকে সার্চ ভিউ পৃষ্ঠায় শেয়ার করা Z-Axis রূপান্তর
- মেলবক্স পৃষ্ঠাগুলির মধ্যে ফেড থ্রু ট্রানজিশন
- কম্পোজ এবং রিপ্লাই FAB এর মধ্যে ফেড থ্রু ট্রানজিশন
- অদৃশ্য হওয়া মেলবক্স শিরোনামের মধ্যে ফেড থ্রু ট্রানজিশন
- নিচের অ্যাপ বারের অ্যাকশনগুলির মধ্যে ফেড থ্রু ট্রানজিশন

তোমার যা লাগবে
- ফ্লাটার ডেভেলপমেন্ট এবং ডার্ট সম্পর্কে প্রাথমিক জ্ঞান।
- একটি কোড সম্পাদক
- একটি অ্যান্ড্রয়েড/আইওএস এমুলেটর বা ডিভাইস
- নমুনা কোড (পরবর্তী ধাপ দেখুন)
ফ্লাটার অ্যাপ তৈরিতে আপনার অভিজ্ঞতার স্তরকে আপনি কীভাবে মূল্যায়ন করবেন?
এই কোডল্যাব থেকে আপনি কী শিখতে চান?
2. আপনার ফ্লাটার ডেভেলপমেন্ট পরিবেশ সেট আপ করুন
এই ল্যাবটি সম্পূর্ণ করার জন্য আপনার দুটি সফটওয়্যারের প্রয়োজন - ফ্লটার SDK এবং একটি এডিটর ।
আপনি এই ডিভাইসগুলির যেকোনো একটি ব্যবহার করে কোডল্যাব চালাতে পারেন:
- আপনার কম্পিউটারের সাথে সংযুক্ত একটি বাস্তব Android বা iOS ডিভাইস এবং ডেভেলপার মোডে সেট করা আছে।
- iOS সিমুলেটর (Xcode টুল ইনস্টল করার প্রয়োজন)।
- অ্যান্ড্রয়েড এমুলেটর (অ্যান্ড্রয়েড স্টুডিওতে সেটআপ প্রয়োজন)।
- একটি ব্রাউজার (ডিবাগিংয়ের জন্য Chrome প্রয়োজন)।
- উইন্ডোজ , লিনাক্স , অথবা ম্যাকওএস ডেস্কটপ অ্যাপ্লিকেশন হিসেবে। আপনি যে প্ল্যাটফর্মে স্থাপন করার পরিকল্পনা করছেন সেখানেই আপনাকে ডেভেলপ করতে হবে। সুতরাং, যদি আপনি একটি উইন্ডোজ ডেস্কটপ অ্যাপ ডেভেলপ করতে চান, তাহলে উপযুক্ত বিল্ড চেইন অ্যাক্সেস করার জন্য আপনাকে উইন্ডোজেই ডেভেলপ করতে হবে। অপারেটিং সিস্টেম-নির্দিষ্ট প্রয়োজনীয়তা রয়েছে যা docs.flutter.dev/desktop এ বিস্তারিতভাবে বর্ণনা করা হয়েছে।
৩. কোডল্যাব স্টার্টার অ্যাপটি ডাউনলোড করুন
বিকল্প ১: GitHub থেকে স্টার্টার কোডল্যাব অ্যাপটি ক্লোন করুন
GitHub থেকে এই কোডল্যাবটি ক্লোন করতে, নিম্নলিখিত কমান্ডগুলি চালান:
git clone https://github.com/material-components/material-components-flutter-motion-codelab.git cd material-components-flutter-motion-codelab
বিকল্প ২: স্টার্টার কোডল্যাব অ্যাপের জিপ ফাইলটি ডাউনলোড করুন
স্টার্টার অ্যাপটি material-components-flutter-motion-codelab-starter ডিরেক্টরিতে রয়েছে।
প্রকল্পের নির্ভরতা যাচাই করুন
প্রকল্পটি অ্যানিমেশন প্যাকেজের উপর নির্ভর করে। pubspec.yaml এ, লক্ষ্য করুন যে dependencies বিভাগে নিম্নলিখিতগুলি অন্তর্ভুক্ত রয়েছে:
animations: ^2.0.0
প্রকল্পটি খুলুন এবং অ্যাপটি চালান।
- আপনার পছন্দের এডিটরে প্রকল্পটি খুলুন।
- আপনার পছন্দের সম্পাদকের জন্য শুরু করুন: টেস্ট ড্রাইভে "অ্যাপটি চালান" নির্দেশাবলী অনুসরণ করুন।
সফল! রিপ্লাইয়ের হোমপেজের স্টার্টার কোডটি আপনার ডিভাইস/এমুলেটরে চলবে। আপনি ইনবক্সে ইমেলের একটি তালিকা দেখতে পাবেন।

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

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

৪. নমুনা অ্যাপ কোডের সাথে পরিচিত হন
কোডটি দেখা যাক। আমরা এমন একটি অ্যাপ সরবরাহ করেছি যা অ্যাপ্লিকেশনের বিভিন্ন স্ক্রিনের মধ্যে রূপান্তরের জন্য অ্যানিমেশন প্যাকেজ ব্যবহার করে।
- হোমপেজ: নির্বাচিত মেলবক্সটি প্রদর্শন করে
- InboxPage : ইমেলের একটি তালিকা প্রদর্শন করে
- MailPreviewCard : একটি ইমেলের প্রিভিউ প্রদর্শন করে।
- MailViewPage: একটি একক, সম্পূর্ণ ইমেল প্রদর্শন করে
- ComposePage: একটি নতুন ইমেল রচনা করার অনুমতি দেয়।
- SearchPage: একটি অনুসন্ধান দৃশ্য প্রদর্শন করে
রাউটার.ডার্ট
প্রথমে, অ্যাপটির রুট নেভিগেশন কীভাবে সেটআপ করা হয় তা বুঝতে, lib ডিরেক্টরিতে router.dart খুলুন:
class ReplyRouterDelegate extends RouterDelegate<ReplyRoutePath>
with ChangeNotifier, PopNavigatorRouterDelegateMixin<ReplyRoutePath> {
ReplyRouterDelegate({required this.replyState})
: navigatorKey = GlobalObjectKey<NavigatorState>(replyState) {
replyState.addListener(() {
notifyListeners();
});
}
@override
final GlobalKey<NavigatorState> navigatorKey;
RouterProvider replyState;
@override
void dispose() {
replyState.removeListener(notifyListeners);
super.dispose();
}
@override
ReplyRoutePath get currentConfiguration => replyState.routePath!;
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<RouterProvider>.value(value: replyState),
],
child: Selector<RouterProvider, ReplyRoutePath?>(
selector: (context, routerProvider) => routerProvider.routePath,
builder: (context, routePath, child) {
return Navigator(
key: navigatorKey,
onPopPage: _handlePopPage,
pages: [
// TODO: Add Shared Z-Axis transition from search icon to search view page (Motion)
const CustomTransitionPage(
transitionKey: ValueKey('Home'),
screen: HomePage(),
),
if (routePath is ReplySearchPath)
const CustomTransitionPage(
transitionKey: ValueKey('Search'),
screen: SearchPage(),
),
],
);
},
),
);
}
bool _handlePopPage(Route<dynamic> route, dynamic result) {
// _handlePopPage should not be called on the home page because the
// PopNavigatorRouterDelegateMixin will bubble up the pop to the
// SystemNavigator if there is only one route in the navigator.
assert(route.willHandlePopInternally ||
replyState.routePath is ReplySearchPath);
final bool didPop = route.didPop(result);
if (didPop) replyState.routePath = const ReplyHomePath();
return didPop;
}
@override
Future<void> setNewRoutePath(ReplyRoutePath configuration) {
replyState.routePath = configuration;
return SynchronousFuture<void>(null);
}
}
এটি আমাদের রুট ন্যাভিগেটর, এবং এটি আমাদের অ্যাপের স্ক্রিনগুলি পরিচালনা করে যা সম্পূর্ণ ক্যানভাস ব্যবহার করে, যেমন HomePage এবং SearchPage । এটি আমাদের অ্যাপের অবস্থা শোনে এবং পরীক্ষা করে যে আমরা ReplySearchPath এ রুট সেট করেছি কিনা। যদি আমরা করে থাকি, তাহলে এটি স্ট্যাকের শীর্ষে SearchPage দিয়ে আমাদের নেভিগেটরটি পুনর্নির্মাণ করে। লক্ষ্য করুন যে আমাদের স্ক্রিনগুলি একটি CustomTransitionPage এ মোড়ানো আছে যেখানে কোনও ট্রানজিশন সংজ্ঞায়িত করা হয়নি। এটি আপনাকে কোনও কাস্টম ট্রানজিশন ছাড়াই স্ক্রিনগুলির মধ্যে নেভিগেট করার একটি উপায় দেখায়।
হোম.ডার্ট
আমরা home.dart এ _BottomAppBarActionItems এর ভিতরে নিম্নলিখিত কাজগুলি করে আমাদের অ্যাপের অবস্থায় ReplySearchPath এ আমাদের রুট সেট করি:
Align(
alignment: AlignmentDirectional.bottomEnd,
child: IconButton(
icon: const Icon(Icons.search),
color: ReplyColors.white50,
onPressed: () {
Provider.of<RouterProvider>(
context,
listen: false,
).routePath = const ReplySearchPath();
},
),
);
আমাদের onPressed প্যারামিটারে, আমরা আমাদের RouterProvider অ্যাক্সেস করি এবং এর routePath কে ReplySearchPath এ সেট করি। আমাদের RouterProvider আমাদের রুট নেভিগেটরের অবস্থা ট্র্যাক করে।
mail_view_router.dart সম্পর্কে
এখন, দেখা যাক আমাদের অ্যাপের অভ্যন্তরীণ নেভিগেশন কীভাবে সেট আপ করা হয়েছে, lib ডিরেক্টরিতে mail_view_router.dart খুলুন। আপনি উপরেরটির মতো একটি নেভিগেটর দেখতে পাবেন:
class MailViewRouterDelegate extends RouterDelegate<void>
with ChangeNotifier, PopNavigatorRouterDelegateMixin {
MailViewRouterDelegate({required this.drawerController});
final AnimationController drawerController;
@override
Widget build(BuildContext context) {
bool _handlePopPage(Route<dynamic> route, dynamic result) {
return false;
}
return Selector<EmailStore, String>(
selector: (context, emailStore) => emailStore.currentlySelectedInbox,
builder: (context, currentlySelectedInbox, child) {
return Navigator(
key: navigatorKey,
onPopPage: _handlePopPage,
pages: [
// TODO: Add Fade through transition between mailbox pages (Motion)
CustomTransitionPage(
transitionKey: ValueKey(currentlySelectedInbox),
screen: InboxPage(
destination: currentlySelectedInbox,
),
)
],
);
},
);
}
...
}
এটি আমাদের অভ্যন্তরীণ নেভিগেটর। এটি আমাদের অ্যাপের অভ্যন্তরীণ স্ক্রিনগুলি পরিচালনা করে যা কেবল ক্যানভাসের মূল অংশ ব্যবহার করে, যেমন InboxPage । আমাদের অ্যাপের বর্তমান অবস্থায় থাকা মেলবক্সের উপর নির্ভর করে InboxPage ইমেলের একটি তালিকা প্রদর্শন করে। যখনই আমাদের অ্যাপের অবস্থার currentlySelectedInbox সম্পত্তিতে কোনও পরিবর্তন হয়, তখন স্ট্যাকের উপরে সঠিক InboxPage দিয়ে নেভিগেটরটি পুনর্নির্মাণ করা হয়।
হোম.ডার্ট
আমরা home.dart এ _HomePageState এর ভেতরে নিম্নলিখিত কাজগুলি করে আমাদের বর্তমান মেলবক্সটিকে আমাদের অ্যাপের অবস্থায় সেট করি:
void _onDestinationSelected(String destination) {
var emailStore = Provider.of<EmailStore>(
context,
listen: false,
);
if (emailStore.onMailView) {
emailStore.currentlySelectedEmailId = -1;
}
if (emailStore.currentlySelectedInbox != destination) {
emailStore.currentlySelectedInbox = destination;
}
setState(() {});
}
আমাদের _onDestinationSelected ফাংশনে, আমরা আমাদের EmailStore অ্যাক্সেস করি এবং এর currentlySelectedInbox কে নির্বাচিত গন্তব্যে সেট করি। আমাদের EmailStore আমাদের অভ্যন্তরীণ নেভিগেটরের অবস্থা ট্র্যাক করে।
হোম.ডার্ট
সবশেষে, ব্যবহৃত নেভিগেশন রাউটিংয়ের একটি উদাহরণ দেখতে, lib ডিরেক্টরিতে home.dart খুলুন। InkWell উইজেটের onTap প্রোপার্টির ভিতরে _ReplyFabState ক্লাসটি খুঁজুন, যা দেখতে এরকম হওয়া উচিত:
onTap: () {
Provider.of<EmailStore>(
context,
listen: false,
).onCompose = true;
Navigator.of(context).push(
PageRouteBuilder(
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
return const ComposePage();
},
),
);
},
এটি দেখায় কিভাবে আপনি কোনও কাস্টম ট্রানজিশন ছাড়াই ইমেল রচনা পৃষ্ঠায় নেভিগেট করতে পারেন। এই কোডল্যাব চলাকালীন, আপনি রিপ্লাইয়ের কোডে ডুব দেবেন যাতে ম্যাটেরিয়াল ট্রানজিশন সেট আপ করা যায় যা অ্যাপ জুড়ে বিভিন্ন নেভিগেশন অ্যাকশনের সাথে তাল মিলিয়ে কাজ করে।
এখন যেহেতু আপনি স্টার্টার কোডের সাথে পরিচিত, আসুন আমাদের প্রথম রূপান্তরটি বাস্তবায়ন করি।
৫. ইমেল তালিকা থেকে ইমেল বিস্তারিত পৃষ্ঠায় কন্টেইনার ট্রান্সফর্ম রূপান্তর যোগ করুন
শুরু করার জন্য, একটি ইমেলে ক্লিক করার সময় আপনাকে একটি ট্রানজিশন যোগ করতে হবে। এই নেভিগেশন পরিবর্তনের জন্য, কন্টেইনার ট্রান্সফর্ম প্যাটার্নটি বেশ উপযুক্ত, কারণ এটি একটি কন্টেইনার সহ UI উপাদানগুলির মধ্যে ট্রানজিশনের জন্য ডিজাইন করা হয়েছে। এই প্যাটার্নটি দুটি UI উপাদানের মধ্যে একটি দৃশ্যমান সংযোগ তৈরি করে।
কোনও কোড যোগ করার আগে, Reply অ্যাপটি চালানোর চেষ্টা করুন এবং একটি ইমেল ক্লিক করুন। এটি একটি সহজ লাফ-কাট করা উচিত, যার অর্থ স্ক্রিনটি কোনও রূপান্তর ছাড়াই প্রতিস্থাপিত হবে:
আগে

নিম্নলিখিত স্নিপেটে দেখানো mail_card_preview.dart এর উপরে অ্যানিমেশন প্যাকেজের জন্য একটি আমদানি যোগ করে শুরু করুন:
মেইল_কার্ড_প্রিভিউ.ডার্ট
import 'package:animations/animations.dart';
এখন যেহেতু আপনার কাছে অ্যানিমেশন প্যাকেজের জন্য একটি আমদানি আছে, আমরা আপনার অ্যাপে সুন্দর ট্রানজিশন যোগ করা শুরু করতে পারি। আসুন একটি StatelessWidget ক্লাস তৈরি করে শুরু করি যেখানে আমাদের OpenContainer উইজেট থাকবে।
mail_card_preview.dart এ, MailPreviewCard এর ক্লাস সংজ্ঞার পরে নিম্নলিখিত কোড স্নিপেট যোগ করুন:
মেইল_কার্ড_প্রিভিউ.ডার্ট
// TODO: Add Container Transform transition from email list to email detail page (Motion)
class _OpenContainerWrapper extends StatelessWidget {
const _OpenContainerWrapper({
required this.id,
required this.email,
required this.closedChild,
});
final int id;
final Email email;
final Widget closedChild;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return OpenContainer(
openBuilder: (context, closedContainer) {
return MailViewPage(id: id, email: email);
},
openColor: theme.cardColor,
closedShape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(0)),
),
closedElevation: 0,
closedColor: theme.cardColor,
closedBuilder: (context, openContainer) {
return InkWell(
onTap: () {
Provider.of<EmailStore>(
context,
listen: false,
).currentlySelectedEmailId = id;
openContainer();
},
child: closedChild,
);
},
);
}
}
এবার আমাদের নতুন র্যাপার ব্যবহার করা যাক। MailPreviewCard ক্লাস ডেফিনিশনের ভেতরে আমরা আমাদের build() ফাংশন থেকে Material উইজেটটি আমাদের নতুন _OpenContainerWrapper দিয়ে মোড়ানো হবে:
মেইল_কার্ড_প্রিভিউ.ডার্ট
// TODO: Add Container Transform transition from email list to email detail page (Motion)
return _OpenContainerWrapper(
id: id,
email: email,
closedChild: Material(
...
আমাদের _OpenContainerWrapper একটি InkWell উইজেট রয়েছে এবং OpenContainer এর রঙের বৈশিষ্ট্যগুলি এটি যে কন্টেইনারটি আবদ্ধ করে তার রঙ নির্ধারণ করে। অতএব, আমরা Material এবং Inkwell উইজেটগুলি সরাতে পারি। ফলাফল কোডটি নিম্নরূপ দেখাবে:
মেইল_কার্ড_প্রিভিউ.ডার্ট
// TODO: Add Container Transform transition from email list to email detail page (Motion)
return _OpenContainerWrapper(
id: id,
email: email,
closedChild: Dismissible(
key: ObjectKey(email),
dismissThresholds: const {
DismissDirection.startToEnd: 0.8,
DismissDirection.endToStart: 0.4,
},
onDismissed: (direction) {
switch (direction) {
case DismissDirection.endToStart:
if (onStarredInbox) {
onStar();
}
break;
case DismissDirection.startToEnd:
onDelete();
break;
default:
}
},
background: _DismissibleContainer(
icon: 'twotone_delete',
backgroundColor: colorScheme.primary,
iconColor: ReplyColors.blue50,
alignment: Alignment.centerLeft,
padding: const EdgeInsetsDirectional.only(start: 20),
),
confirmDismiss: (direction) async {
if (direction == DismissDirection.endToStart) {
if (onStarredInbox) {
return true;
}
onStar();
return false;
} else {
return true;
}
},
secondaryBackground: _DismissibleContainer(
icon: 'twotone_star',
backgroundColor: currentEmailStarred
? colorScheme.secondary
: theme.scaffoldBackgroundColor,
iconColor: currentEmailStarred
? colorScheme.onSecondary
: colorScheme.onBackground,
alignment: Alignment.centerRight,
padding: const EdgeInsetsDirectional.only(end: 20),
),
child: mailPreview,
),
);
এই পর্যায়ে, আপনার একটি সম্পূর্ণরূপে কার্যকরী কন্টেইনার ট্রান্সফর্ম থাকা উচিত। একটি ইমেলের উপর ক্লিক করলে তালিকার আইটেমটি একটি বিশদ স্ক্রিনে প্রসারিত হয় এবং ইমেলের তালিকাটি পিছিয়ে যায়। পিছনে টিপলে ইমেলের তালিকাটি স্কেল করার সময় ইমেলের বিবরণ স্ক্রিনটি আবার একটি তালিকা আইটেমে সঙ্কুচিত হয়।
পরে

৬. FAB থেকে কম্পোজ ইমেল পৃষ্ঠায় কন্টেইনার ট্রান্সফর্ম ট্রানজিশন যোগ করুন
আসুন কন্টেইনার ট্রান্সফর্মের সাথে এগিয়ে যাই এবং Floating Action Button থেকে ComposePage এ একটি ট্রানজিশন যোগ করি যা FAB-কে ব্যবহারকারীর লেখা একটি নতুন ইমেলে প্রসারিত করে। প্রথমে, অ্যাপটি পুনরায় চালান এবং FAB-তে ক্লিক করুন যাতে ইমেল কম্পোজ স্ক্রিন চালু করার সময় কোনও ট্রানজিশন না হয়।
আগে

আমরা যেভাবে এই রূপান্তরটি কনফিগার করব তা শেষ ধাপে আমরা যেভাবে করেছি তার সাথে অনেকটা মিল থাকবে, কারণ আমরা একই উইজেট ক্লাস, OpenContainer ব্যবহার করছি।
home.dart এ, ফাইলের উপরে package:animations/animations.dart ইম্পোর্ট করি এবং _ReplyFabState build() পদ্ধতিটি পরিবর্তন করি। ফিরে আসা Material উইজেটটিকে একটি OpenContainer উইজেট দিয়ে মুড়ে ফেলি:
হোম.ডার্ট
// TODO: Add Container Transform from FAB to compose email page (Motion)
return OpenContainer(
openBuilder: (context, closedContainer) {
return const ComposePage();
},
openColor: theme.cardColor,
onClosed: (success) {
Provider.of<EmailStore>(
context,
listen: false,
).onCompose = false;
},
closedShape: circleFabBorder,
closedColor: theme.colorScheme.secondary,
closedElevation: 6,
closedBuilder: (context, openContainer) {
return Material(
color: theme.colorScheme.secondary,
...
আমাদের পূর্ববর্তী OpenContainer উইজেট কনফিগার করার জন্য ব্যবহৃত প্যারামিটারগুলি ছাড়াও, onClosed এখন সেট করা হচ্ছে। onClosed হল একটি ClosedCallback যা OpenContainer রুট পপ করা হলে বা বন্ধ অবস্থায় ফিরে গেলে কল করা হয়। সেই লেনদেনের রিটার্ন মান একটি আর্গুমেন্ট হিসাবে এই ফাংশনে পাস করা হয়। আমরা এই Callback আমাদের অ্যাপের সরবরাহকারীকে জানাতে ব্যবহার করি যে আমরা ComposePage রুট ছেড়ে চলে এসেছি, যাতে এটি সমস্ত শ্রোতাদের অবহিত করতে পারে।
আমাদের শেষ ধাপের মতো, আমরা আমাদের উইজেট থেকে Material উইজেটটি সরিয়ে দেব কারণ OpenContainer উইজেট closedBuilder দ্বারা ফেরত পাঠানো উইজেটের রঙ closedColor দিয়ে পরিচালনা করে। আমরা আমাদের InkWell উইজেটের onTap এর ভিতরে থাকা Navigator.push() কলটিও সরিয়ে দেব এবং OpenContainer উইজেটের closedBuilder দ্বারা প্রদত্ত openContainer() Callback দিয়ে এটি প্রতিস্থাপন করব, যেহেতু এখন OpenContainer উইজেটটি নিজস্ব রাউটিং পরিচালনা করছে।
ফলাফল কোডটি নিম্নরূপ:
হোম.ডার্ট
// TODO: Add Container Transform from FAB to compose email page (Motion)
return OpenContainer(
openBuilder: (context, closedContainer) {
return const ComposePage();
},
openColor: theme.cardColor,
onClosed: (success) {
Provider.of<EmailStore>(
context,
listen: false,
).onCompose = false;
},
closedShape: circleFabBorder,
closedColor: theme.colorScheme.secondary,
closedElevation: 6,
closedBuilder: (context, openContainer) {
return Tooltip(
message: tooltip,
child: InkWell(
customBorder: circleFabBorder,
onTap: () {
Provider.of<EmailStore>(
context,
listen: false,
).onCompose = true;
openContainer();
},
child: SizedBox(
height: _mobileFabDimension,
width: _mobileFabDimension,
child: Center(
child: fabSwitcher,
),
),
),
);
},
);
এখন কিছু পুরনো কোড পরিষ্কার করার জন্য। যেহেতু আমাদের OpenContainer উইজেট এখন আমাদের অ্যাপের প্রোভাইডারকে onClosed ClosedCallback এর মাধ্যমে সূচিত করে যে আমরা আর ComposePage এ নেই, তাই আমরা mail_view_router.dart ব্যবহার করে আমাদের পূর্ববর্তী বাস্তবায়নটি সরিয়ে ফেলতে পারি:
mail_view_router.dart সম্পর্কে
// TODO: Add Container Transform from FAB to compose email page (Motion)
emailStore.onCompose = false; /// delete this line
return SynchronousFuture<bool>(true);
এই ধাপের জন্য এটুকুই! আপনার FAB থেকে কম্পোজ স্ক্রিনে একটি রূপান্তর থাকা উচিত যা দেখতে নিচের মতো হবে:
পরে

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

শুরু করতে, আমাদের router.dart ফাইলে যাওয়া যাক। আমাদের ReplySearchPath ক্লাসের সংজ্ঞার পরে নিম্নলিখিত স্নিপেটটি যোগ করুন:
রাউটার.ডার্ট
// TODO: Add Shared Z-Axis transition from search icon to search view page (Motion)
class SharedAxisTransitionPageWrapper extends Page {
const SharedAxisTransitionPageWrapper(
{required this.screen, required this.transitionKey})
: super(key: transitionKey);
final Widget screen;
final ValueKey transitionKey;
@override
Route createRoute(BuildContext context) {
return PageRouteBuilder(
settings: this,
transitionsBuilder: (context, animation, secondaryAnimation, child) {
return SharedAxisTransition(
fillColor: Theme.of(context).cardColor,
animation: animation,
secondaryAnimation: secondaryAnimation,
transitionType: SharedAxisTransitionType.scaled,
child: child,
);
},
pageBuilder: (context, animation, secondaryAnimation) {
return screen;
});
}
}
এখন, আমাদের নতুন SharedAxisTransitionPageWrapper ব্যবহার করে আমরা আমাদের কাঙ্ক্ষিত রূপান্তরটি অর্জন করি। আমাদের ReplyRouterDelegate ক্লাস সংজ্ঞার ভিতরে, pages সম্পত্তির অধীনে, আমাদের অনুসন্ধান স্ক্রিনটি CustomTransitionPage এর পরিবর্তে SharedAxisTransitionPageWrapper দিয়ে মোড়ানো যাক:
রাউটার.ডার্ট
return Navigator(
key: navigatorKey,
onPopPage: _handlePopPage,
pages: [
// TODO: Add Shared Z-Axis transition from search icon to search view page (Motion)
const CustomTransitionPage(
transitionKey: ValueKey('Home'),
screen: HomePage(),
),
if (routePath is ReplySearchPath)
const SharedAxisTransitionPageWrapper(
transitionKey: ValueKey('Search'),
screen: SearchPage(),
),
],
);
এখন অ্যাপটি পুনরায় চালানোর চেষ্টা করুন।

সবকিছু দারুন দেখাচ্ছে! যখন আপনি নীচের অ্যাপ বারে সার্চ আইকনে ক্লিক করেন, তখন একটি শেয়ার্ড অক্ষের রূপান্তর অনুসন্ধান পৃষ্ঠাটিকে দৃশ্যমান করে তোলে। তবে, লক্ষ্য করুন যে কীভাবে হোম পৃষ্ঠাটি স্কেল করে না এবং অনুসন্ধান পৃষ্ঠাটি স্কেল করার সময় স্থির থাকে। উপরন্তু, পিছনের বোতামটি টিপলে, হোম পৃষ্ঠাটি দৃশ্যমান হয় না, বরং অনুসন্ধান পৃষ্ঠাটি দৃশ্যমান না হওয়ার সাথে সাথে এটি স্থির থাকে। সুতরাং আমরা এখনও শেষ করিনি।
আসুন CustomTransitionPage এর পরিবর্তে আমাদের SharedAxisTransitionWrapper দিয়ে HomePage মোড়ানোর মাধ্যমে উভয় সমস্যার সমাধান করি:
রাউটার.ডার্ট
return Navigator(
key: navigatorKey,
onPopPage: _handlePopPage,
pages: [
// TODO: Add Shared Z-Axis transition from search icon to search view page (Motion)
const SharedAxisTransitionPageWrapper(
transitionKey: ValueKey('home'),
screen: HomePage(),
),
if (routePath is ReplySearchPath)
const SharedAxisTransitionPageWrapper(
transitionKey: ValueKey('search'),
screen: SearchPage(),
),
],
);
ব্যস! এবার অ্যাপটি পুনরায় চালু করে সার্চ আইকনে ট্যাপ করার চেষ্টা করুন। হোম এবং সার্চ ভিউ স্ক্রিনগুলি একই সাথে বিবর্ণ হওয়া উচিত এবং Z-অক্ষ বরাবর গভীরভাবে স্কেল করা উচিত, যা দুটি স্ক্রিনের মধ্যে একটি নিরবচ্ছিন্ন প্রভাব তৈরি করে।
পরে

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

শুরু করতে, আমাদের mail_view_router.dart ফাইলে যাওয়া যাক। আমাদের MailViewRouterDelegate ক্লাসের সংজ্ঞার পরে নিম্নলিখিত স্নিপেটটি যোগ করুন:
mail_view_router.dart সম্পর্কে
// TODO: Add Fade through transition between mailbox pages (Motion)
class FadeThroughTransitionPageWrapper extends Page {
const FadeThroughTransitionPageWrapper({
required this.mailbox,
required this.transitionKey,
}) : super(key: transitionKey);
final Widget mailbox;
final ValueKey transitionKey;
@override
Route createRoute(BuildContext context) {
return PageRouteBuilder(
settings: this,
transitionsBuilder: (context, animation, secondaryAnimation, child) {
return FadeThroughTransition(
fillColor: Theme.of(context).scaffoldBackgroundColor,
animation: animation,
secondaryAnimation: secondaryAnimation,
child: child,
);
},
pageBuilder: (context, animation, secondaryAnimation) {
return mailbox;
});
}
}
আমাদের শেষ ধাপের মতো, আসুন আমরা আমাদের কাঙ্ক্ষিত রূপান্তরটি অর্জনের জন্য আমাদের নতুন FadeThroughTransitionPageWrapper ব্যবহার করি। আমাদের MailViewRouterDelegate ক্লাস সংজ্ঞার ভিতরে, pages প্রপার্টির অধীনে, আমাদের মেলবক্স স্ক্রিনটি CustomTransitionPage দিয়ে মোড়ানোর পরিবর্তে, FadeThroughTransitionPageWrapper ব্যবহার করি:
mail_view_router.dart সম্পর্কে
return Navigator(
key: navigatorKey,
onPopPage: _handlePopPage,
pages: [
// TODO: Add Fade through transition between mailbox pages (Motion)
FadeThroughTransitionPageWrapper(
mailbox: InboxPage(destination: currentlySelectedInbox),
transitionKey: ValueKey(currentlySelectedInbox),
),
],
);
অ্যাপটি পুনরায় চালান। যখন আপনি নীচের নেভিগেশন ড্রয়ারটি খুলবেন এবং মেলবক্সগুলি পরিবর্তন করবেন, তখন বর্তমান ইমেলের তালিকাটি বিবর্ণ এবং স্কেল আউট হয়ে যাবে এবং নতুন তালিকাটি বিবর্ণ এবং স্কেল ইন হয়ে যাবে। চমৎকার!
পরে

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

কোডল্যাবের বাকি অংশের জন্য আমরা home.dart এ কাজ করব, তাই অ্যানিমেশন প্যাকেজের জন্য আমদানি যোগ করার বিষয়ে চিন্তা করবেন না কারণ আমরা ইতিমধ্যেই ধাপ ২-এ home.dart এর জন্য করেছি।
পরবর্তী দুটি ট্রানজিশন কনফিগার করার পদ্ধতিটি অনেকটা একই রকম হবে, কারণ তারা সবাই একটি পুনঃব্যবহারযোগ্য ক্লাস, _FadeThroughTransitionSwitcher ব্যবহার করবে।
home.dart এ _ReplyFabState এর অধীনে নিম্নলিখিত স্নিপেটটি যোগ করা যাক:
হোম.ডার্ট
// TODO: Add Fade through transition between compose and reply FAB (Motion)
class _FadeThroughTransitionSwitcher extends StatelessWidget {
const _FadeThroughTransitionSwitcher({
required this.fillColor,
required this.child,
});
final Widget child;
final Color fillColor;
@override
Widget build(BuildContext context) {
return PageTransitionSwitcher(
transitionBuilder: (child, animation, secondaryAnimation) {
return FadeThroughTransition(
fillColor: fillColor,
child: child,
animation: animation,
secondaryAnimation: secondaryAnimation,
);
},
child: child,
);
}
}
এখন, আমাদের _ReplyFabState এ, fabSwitcher উইজেটটি খুঁজুন। fabSwitcher ইমেল ভিউতে আছে কিনা তার উপর নির্ভর করে একটি ভিন্ন আইকন প্রদান করে। আসুন এটি আমাদের _FadeThroughTransitionSwitcher দিয়ে শেষ করি:
হোম.ডার্ট
// TODO: Add Fade through transition between compose and reply FAB (Motion)
static final fabKey = UniqueKey();
static const double _mobileFabDimension = 56;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final circleFabBorder = const CircleBorder();
return Selector<EmailStore, bool>(
selector: (context, emailStore) => emailStore.onMailView,
builder: (context, onMailView, child) {
// TODO: Add Fade through transition between compose and reply FAB (Motion)
final fabSwitcher = _FadeThroughTransitionSwitcher(
fillColor: Colors.transparent,
child: onMailView
? Icon(
Icons.reply_all,
key: fabKey,
color: Colors.black,
)
: const Icon(
Icons.create,
color: Colors.black,
),
);
...
আমরা আমাদের _FadeThroughTransitionSwitcher একটি স্বচ্ছ fillColor দেই, যাতে ট্রানজিশনের সময় উপাদানগুলির মধ্যে কোনও পটভূমি না থাকে। আমরা একটি UniqueKey ও তৈরি করি এবং এটি একটি আইকনে বরাদ্দ করি।
এখন, এই ধাপে, আপনার একটি সম্পূর্ণ অ্যানিমেটেড প্রাসঙ্গিক FAB থাকা উচিত। ইমেল ভিউতে প্রবেশ করলে পুরাতন FAB আইকনটি বিবর্ণ এবং স্কেল আউট হয়ে যায় এবং নতুনটি বিবর্ণ এবং স্কেল ইন হয়ে যায়।
পরে

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

এই কোডল্যাবের বাকি কাজ দ্রুত হবে কারণ আমরা আমাদের শেষ ধাপে _FadeThroughTransitionSwitcher এ বেশিরভাগ কাজ ইতিমধ্যেই করে ফেলেছি।
এখন, home.dart এ আমাদের _AnimatedBottomAppBar ক্লাসে যাই এবং আমাদের ট্রানজিশন যোগ করি। আমরা আমাদের শেষ ধাপ থেকে _FadeThroughTransitionSwitcher পুনঃব্যবহার করব, এবং আমাদের onMailView শর্তসাপেক্ষে মোড়ানো হবে, যা হয় একটি খালি SizedBox ফেরত দেবে, অথবা একটি মেলবক্স শিরোনাম যা নীচের ড্রয়ারের সাথে সিঙ্কে বিবর্ণ হয়ে যাবে:
হোম.ডার্ট
...
const _ReplyLogo(),
const SizedBox(width: 10),
// TODO: Add Fade through transition between disappearing mailbox title (Motion)
_FadeThroughTransitionSwitcher(
fillColor: Colors.transparent,
child: onMailView
? const SizedBox(width: 48)
: FadeTransition(
opacity: fadeOut,
child: Selector<EmailStore, String>(
selector: (context, emailStore) =>
emailStore.currentlySelectedInbox,
builder: (
context,
currentlySelectedInbox,
child,
) {
return Text(
currentlySelectedInbox,
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(
color: ReplyColors.white50,
),
);
},
),
),
),
এই তো, এই ধাপটি শেষ!
অ্যাপটি পুনরায় চালান। যখন আপনি একটি ইমেল খুলবেন এবং আপনাকে ইমেল ভিউতে নিয়ে যাওয়া হবে, তখন নীচের অ্যাপ বারে থাকা মেলবক্সের শিরোনামটি বিবর্ণ হয়ে যাবে এবং স্কেল হয়ে যাবে। অসাধারণ!
পরে

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

শেষ ধাপের মতো, আমরা আবার আমাদের _FadeThroughTransitionSwitcher ব্যবহার করব। কাঙ্ক্ষিত ট্রানজিশন অর্জন করতে আমাদের _BottomAppBarActionItems ক্লাসের সংজ্ঞায় যান এবং আমাদের build() ফাংশনের রিটার্ন উইজেটটি _FadeThroughTransitionSwitcher দিয়ে মুড়ে দিন:
হোম.ডার্ট
// TODO: Add Fade through transition between bottom app bar actions (Motion)
return _FadeThroughTransitionSwitcher(
fillColor: Colors.transparent,
child: drawerVisible
? Align(
key: UniqueKey(),
alignment: AlignmentDirectional.bottomEnd,
child: IconButton(
icon: const Icon(Icons.settings),
color: ReplyColors.white50,
onPressed: () async {
drawerController.reverse();
showModalBottomSheet(
context: context,
shape: RoundedRectangleBorder(
borderRadius: modalBorder,
),
builder: (context) => const SettingsBottomSheet(),
);
},
),
)
: onMailView
...
এবার চেষ্টা করে দেখা যাক! যখন আপনি একটি ইমেল খুলবেন এবং ইমেল ভিউতে নিয়ে যাবেন, তখন পুরানো নীচের অ্যাপ বারের অ্যাকশনগুলি বিবর্ণ এবং স্কেল আউট হয়ে যাবে এবং নতুন অ্যাকশনগুলি বিবর্ণ এবং স্কেল ইন হয়ে যাবে। দারুন!
পরে

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

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



