ফ্লটারের জন্য উপাদান গতির সাথে সুন্দর রূপান্তর তৈরি করা

1. ভূমিকা

মেটেরিয়াল ডিজাইন হল সাহসী এবং সুন্দর ডিজিটাল পণ্য তৈরির একটি সিস্টেম। নীতি এবং উপাদানগুলির একটি ধারাবাহিক সেটের অধীনে শৈলী, ব্র্যান্ডিং, মিথস্ক্রিয়া এবং গতি একত্রিত করার মাধ্যমে, পণ্য দলগুলি তাদের সর্বশ্রেষ্ঠ নকশা সম্ভাবনা উপলব্ধি করতে পারে।

logo_components_color_2x_web_96dp.png

মেটেরিয়াল কম্পোনেন্টস (MDC) ডেভেলপারদের ম্যাটেরিয়াল ডিজাইন বাস্তবায়নে সহায়তা করে। Google-এ প্রকৌশলী এবং UX ডিজাইনারদের একটি দল দ্বারা তৈরি, MDC কয়েক ডজন সুন্দর এবং কার্যকরী UI উপাদান বৈশিষ্ট্যযুক্ত এবং এটি Android, iOS, ওয়েব এবং Flutter.material.io/develop-এর জন্য উপলব্ধ

ফ্লটারের জন্য উপাদানের গতি ব্যবস্থা কী?

ফ্লটারের জন্য ম্যাটেরিয়াল মোশন সিস্টেম হল অ্যানিমেশন প্যাকেজের মধ্যে পরিবর্তনের প্যাটার্নের একটি সেট যা ব্যবহারকারীদের একটি অ্যাপ বুঝতে এবং নেভিগেট করতে সাহায্য করতে পারে, যেমনটি মেটেরিয়াল ডিজাইন নির্দেশিকাতে বর্ণিত হয়েছে।

চারটি প্রধান উপাদান রূপান্তর নিদর্শন নিম্নরূপ:

  • ধারক রূপান্তর: UI উপাদানগুলির মধ্যে রূপান্তর যা একটি ধারক অন্তর্ভুক্ত করে; নির্বিঘ্নে একটি উপাদানকে অন্যটিতে রূপান্তর করে দুটি স্বতন্ত্র UI উপাদানের মধ্যে একটি দৃশ্যমান সংযোগ তৈরি করে।

11807bdf36c66657.gif

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

71218f390abae07e.gif

  • ফেইড থ্রু: UI উপাদানগুলির মধ্যে রূপান্তর যা একে অপরের সাথে শক্তিশালী সম্পর্ক নেই; ইনকামিং এলিমেন্টের স্কেল সহ একটি অনুক্রমিক ফেইড আউট এবং ফেড ইন ব্যবহার করে।

385ba37b8da68969.gif

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

cfc40fd6e27753b6.gif

ফ্লাটার অ্যানিমেশন লাইব্রেরি ( flutter/animation.dart ) এবং Flutter উপাদান লাইব্রেরি ( flutter/material.dart ) উভয়ের উপরে নির্মিত এই প্যাটার্নগুলির জন্য অ্যানিমেশন প্যাকেজ ট্রানজিশন উইজেটগুলি অফার করে :

এই কোডল্যাবে আপনি ফ্লাটার ফ্রেমওয়ার্ক এবং মেটেরিয়াল লাইব্রেরির উপরে নির্মিত ম্যাটেরিয়াল ট্রানজিশন ব্যবহার করবেন, যার অর্থ আপনি উইজেট নিয়ে কাজ করবেন। :)

আপনি কি নির্মাণ করবেন

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

রিপ্লাই অ্যাপের জন্য স্টার্টার কোড প্রদান করা হবে, এবং আপনি অ্যাপটিতে নিম্নলিখিত উপাদানের রূপান্তরগুলিকে অন্তর্ভুক্ত করবেন, যা নীচে সম্পূর্ণ কোডল্যাবের জিআইএফ-এ দেখা যাবে:

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

b26fe84fed12d17d.gif

আপনি কি প্রয়োজন হবে

  • ফ্লটার ডেভেলপমেন্ট এবং ডার্ট সম্পর্কে প্রাথমিক জ্ঞান
  • একটি কোড সম্পাদক
  • একটি Android/iOS এমুলেটর বা ডিভাইস
  • নমুনা কোড (পরবর্তী ধাপ দেখুন)

ফ্লাটার অ্যাপ তৈরি করার অভিজ্ঞতার স্তরকে আপনি কীভাবে রেট করবেন?

নবজাতক মধ্যবর্তী দক্ষ

আপনি এই কোডল্যাব থেকে কি শিখতে চান?

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

2. আপনার ফ্লটার ডেভেলপমেন্ট এনভায়রনমেন্ট সেট আপ করুন

এই ল্যাবটি সম্পূর্ণ করার জন্য আপনার দুটি টুকরো সফ্টওয়্যার প্রয়োজন - ফ্লাটার SDK এবং একটি সম্পাদক

আপনি এই ডিভাইসগুলির যেকোনো একটি ব্যবহার করে কোডল্যাব চালাতে পারেন:

  • আপনার কম্পিউটারের সাথে সংযুক্ত এবং বিকাশকারী মোডে সেট করা একটি শারীরিক Android বা iOS ডিভাইস৷
  • আইওএস সিমুলেটর (এক্সকোড সরঞ্জাম ইনস্টল করা প্রয়োজন)।
  • অ্যান্ড্রয়েড এমুলেটর (অ্যান্ড্রয়েড স্টুডিওতে সেটআপ প্রয়োজন)।
  • একটি ব্রাউজার (ডিবাগিংয়ের জন্য Chrome প্রয়োজন)।
  • একটি Windows , Linux , বা macOS ডেস্কটপ অ্যাপ্লিকেশন হিসাবে। আপনি যে প্ল্যাটফর্মে স্থাপন করার পরিকল্পনা করছেন সেখানে আপনাকে অবশ্যই বিকাশ করতে হবে। সুতরাং, আপনি যদি একটি উইন্ডোজ ডেস্কটপ অ্যাপ বিকাশ করতে চান, তাহলে যথাযথ বিল্ড চেইন অ্যাক্সেস করতে আপনাকে অবশ্যই উইন্ডোজে বিকাশ করতে হবে। অপারেটিং সিস্টেম-নির্দিষ্ট প্রয়োজনীয়তা রয়েছে যা docs.flutter.dev/desktop- এ বিস্তারিতভাবে কভার করা হয়েছে।

3. কোডল্যাব স্টার্টার অ্যাপটি ডাউনলোড করুন

বিকল্প 1: GitHub থেকে স্টার্টার কোডল্যাব অ্যাপটি ক্লোন করুন

GitHub থেকে এই কোডল্যাব ক্লোন করতে, নিম্নলিখিত কমান্ডগুলি চালান:

git clone https://github.com/material-components/material-components-flutter-motion-codelab.git
cd material-components-flutter-motion-codelab

বিকল্প 2: স্টার্টার কোডল্যাব অ্যাপ জিপ ফাইলটি ডাউনলোড করুন

স্টার্টার অ্যাপটি material-components-flutter-motion-codelab-starter ডিরেক্টরিতে রয়েছে।

প্রকল্প নির্ভরতা যাচাই করুন

প্রকল্পটি অ্যানিমেশন প্যাকেজের উপর নির্ভর করে। pubspec.yaml এ, লক্ষ্য করুন dependencies বিভাগে নিম্নলিখিতগুলি অন্তর্ভুক্ত রয়েছে:

animations: ^2.0.0

প্রকল্পটি খুলুন এবং অ্যাপটি চালান

  1. আপনার পছন্দের সম্পাদকে প্রকল্পটি খুলুন।
  2. Get Started: আপনার নির্বাচিত সম্পাদকের জন্য টেস্ট ড্রাইভ -এ "অ্যাপ চালাতে" নির্দেশাবলী অনুসরণ করুন।

সফলতার ! উত্তরের হোমপেজের জন্য স্টার্টার কোড আপনার ডিভাইস/এমুলেটরে চালানো উচিত। আপনার ইমেলের একটি তালিকা সম্বলিত ইনবক্স দেখতে হবে।

হোম পেজ উত্তর

ঐচ্ছিক: ডিভাইস অ্যানিমেশন ধীর করুন

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

d23a7bfacffac509.gif

ঐচ্ছিক: ডার্ক মোড

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

87618d8418eee19e.gif

4. নমুনা অ্যাপ কোডের সাথে পরিচিত হন

চলুন কোড তাকান. আমরা একটি অ্যাপ প্রদান করেছি যেটি অ্যানিমেশন প্যাকেজ ব্যবহার করে অ্যাপ্লিকেশানের বিভিন্ন স্ক্রিনের মধ্যে স্থানান্তর করতে পারে৷

  • হোমপেজ: নির্বাচিত মেইলবক্স প্রদর্শন করে
  • ইনবক্সপেজ : ইমেলের একটি তালিকা প্রদর্শন করে
  • MailPreviewCard : একটি ইমেলের পূর্বরূপ প্রদর্শন করে
  • MailViewPage: একটি একক, সম্পূর্ণ ইমেল প্রদর্শন করে
  • কম্পোজপেজ: একটি নতুন ইমেল রচনার অনুমতি দেয়
  • অনুসন্ধান পৃষ্ঠা: একটি অনুসন্ধান দৃশ্য প্রদর্শন করে

রাউটার.ডার্ট

প্রথমত, অ্যাপের রুট নেভিগেশন কীভাবে সেটআপ করা হয় তা বুঝতে, 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

আমরা 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 ইমেলের একটি তালিকা প্রদর্শন করে। ন্যাভিগেটরটিকে স্ট্যাকের উপরে সঠিক InboxPage দিয়ে পুনর্নির্মাণ করা হয়, যখনই আমাদের অ্যাপের অবস্থার currentlySelectedInbox সিলেক্টেড ইনবক্স প্রপার্টিতে কোনো পরিবর্তন হয়।

home.dart

আমরা 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 আমাদের অভ্যন্তরীণ নেভিগেটর অবস্থার উপর নজর রাখে।

home.dart

সবশেষে, একটি ন্যাভিগেশন রাউটিং ব্যবহার করা হচ্ছে তার উদাহরণ দেখতে, 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();
     },
   ),
 );
},

এটি দেখায় কিভাবে আপনি কোনো কাস্টম ট্রানজিশন ছাড়াই ইমেল রচনা পৃষ্ঠায় নেভিগেট করতে পারেন। এই কোডল্যাব চলাকালীন, আপনি ম্যাটেরিয়াল ট্রানজিশন সেট আপ করতে রিপ্লাই এর কোডে ডুব দেবেন যা অ্যাপ জুড়ে বিভিন্ন নেভিগেশন অ্যাকশনের সাথে মিলেমিশে কাজ করে।

এখন যেহেতু আপনি স্টার্টার কোডের সাথে পরিচিত, আসুন আমাদের প্রথম রূপান্তরটি বাস্তবায়ন করি।

5. ইমেল তালিকা থেকে ইমেল বিস্তারিত পৃষ্ঠায় কনটেইনার ট্রান্সফর্ম ট্রানজিশন যোগ করুন

শুরু করার জন্য, একটি ইমেলে ক্লিক করার সময় আপনি একটি পরিবর্তন যোগ করবেন। এই নেভিগেশন পরিবর্তনের জন্য, কন্টেইনার ট্রান্সফর্ম প্যাটার্নটি উপযুক্ত, কারণ এটি একটি ধারক অন্তর্ভুক্ত UI উপাদানগুলির মধ্যে পরিবর্তনের জন্য ডিজাইন করা হয়েছে। এই প্যাটার্ন দুটি UI উপাদানের মধ্যে একটি দৃশ্যমান সংযোগ তৈরি করে।

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

আগে

48b00600f73c7778.gif

নিম্নলিখিত স্নিপেটে দেখানো হিসাবে mail_card_preview.dart এর শীর্ষে অ্যানিমেশন প্যাকেজের জন্য একটি আমদানি যোগ করে শুরু করুন:

mail_card_preview.dart

import 'package:animations/animations.dart';

এখন আপনার কাছে অ্যানিমেশন প্যাকেজের জন্য একটি আমদানি আছে, আমরা আপনার অ্যাপে সুন্দর রূপান্তর যোগ করা শুরু করতে পারি। আসুন একটি StatelessWidget ক্লাস তৈরি করে শুরু করি যা আমাদের OpenContainer উইজেটকে রাখবে।

mail_card_preview.dart এ, MailPreviewCard এর ক্লাস সংজ্ঞার পরে নিম্নলিখিত কোড স্নিপেট যোগ করুন:

mail_card_preview.dart

// 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() ফাংশন থেকে আমাদের নতুন _OpenContainerWrapper এর সাথে Material উইজেটটি মোড়ানো করব:

mail_card_preview.dart

// TODO: Add Container Transform transition from email list to email detail page (Motion)
return _OpenContainerWrapper(
 id: id,
 email: email,
 closedChild: Material(
...

আমাদের _OpenContainerWrapper একটি InkWell উইজেট রয়েছে এবং OpenContainer এর রঙের বৈশিষ্ট্যগুলি এটিকে ঘেরা কন্টেইনারটির রঙ নির্ধারণ করে। অতএব, আমরা উপাদান এবং ইনকওয়েল উইজেটগুলি সরাতে পারি। ফলাফল কোড নিম্নলিখিত হিসাবে দেখায়:

mail_card_preview.dart

// 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,
 ),
);

এই পর্যায়ে, আপনার একটি সম্পূর্ণরূপে কাজ করা পাত্রে রূপান্তর হওয়া উচিত। একটি ইমেলের উপর ক্লিক করা ইমেলের তালিকা প্রত্যাহার করার সময় তালিকা আইটেমটিকে একটি বিশদ স্ক্রিনে প্রসারিত করে। ইমেলের তালিকায় স্কেল করার সময় পিছনে টিপলে ইমেলের বিবরণের স্ক্রীনটি একটি তালিকা আইটেমে ফিরে আসে।

পরে

663e8594319bdee3.gif

6. ইমেল পৃষ্ঠা রচনা করতে FAB থেকে কনটেইনার ট্রান্সফর্ম ট্রানজিশন যোগ করুন

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

আগে

4aa2befdc5170c60.gif

আমরা যেভাবে এই ট্রানজিশনটি কনফিগার করি সেটি শেষ ধাপে আমরা যেভাবে করেছিলাম তার অনুরূপ হবে, যেহেতু আমরা একই উইজেট ক্লাস, OpenContainer ব্যবহার করছি।

home.dart এ, ফাইলের শীর্ষে package:animations/animations.dart আমদানি করি এবং _ReplyFabState build() পদ্ধতি পরিবর্তন করি। ফিরে আসা Material উইজেটটিকে একটি OpenContainer উইজেট দিয়ে মোড়ানো যাক:

home.dart

// 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() Callback OpenContainer উইজেটের closedBuilder দ্বারা প্রদত্ত কলব্যাকের সাথে প্রতিস্থাপন করব, যেহেতু এখন OpenContainer উইজেট তার নিজস্ব রাউটিং পরিচালনা করছে।

ফলাফল কোড নিম্নরূপ:

home.dart

// 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 থেকে একটি রূপান্তর হওয়া উচিত:

পরে

5c7ad1b4b40f9f0c.gif

7. সার্চ ভিউ পেজে সার্চ আইকন থেকে শেয়ার্ড জেড-অ্যাক্সিস ট্রানজিশন যোগ করুন

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

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

আগে

df7683a8ad7b920e.gif

শুরু করতে, আসুন আমাদের 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(),
     ),
 ],
);

এখন অ্যাপটি পুনরায় চালানোর চেষ্টা করুন।

81b3ea098926931.gif

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

আসুন একটি 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-অক্ষ বরাবর বিবর্ণ এবং স্কেল করা উচিত, যা দুটি পর্দার মধ্যে একটি বিরামহীন প্রভাব তৈরি করে।

পরে

462d890086a3d18a.gif

8. মেলবক্স পৃষ্ঠাগুলির মধ্যে স্থানান্তরের মাধ্যমে ফেড যোগ করুন৷

এই ধাপে, আমরা বিভিন্ন মেলবক্সের মধ্যে একটি পরিবর্তন যোগ করব। যেহেতু আমরা স্থানিক বা শ্রেণিবদ্ধ সম্পর্কের উপর জোর দিতে চাই না, তাই ইমেলের তালিকার মধ্যে একটি সাধারণ "অদলবদল" করতে আমরা একটি ফেড থ্রু ব্যবহার করব।

কোনও অতিরিক্ত কোড যোগ করার আগে, অ্যাপটি চালানোর চেষ্টা করুন, নীচের অ্যাপ বারে উত্তর লোগোতে আলতো চাপুন এবং মেলবক্সগুলি স্যুইচ করুন৷ ইমেলের তালিকা কোন পরিবর্তন ছাড়াই পরিবর্তন করা উচিত।

আগে

89033988ce26b92e.gif

শুরু করতে, আসুন আমাদের 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),
   ),
 ],
);

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

পরে

8186940082b630d.gif

9. রচনা এবং উত্তর FAB এর মধ্যে পরিবর্তনের মাধ্যমে ফেড যোগ করুন

এই ধাপে, আমরা বিভিন্ন FAB আইকনের মধ্যে একটি পরিবর্তন যোগ করব। যেহেতু আমরা স্থানিক বা শ্রেণিবদ্ধ সম্পর্কের উপর জোর দিতে চাই না, তাই আমরা FAB-এর আইকনগুলির মধ্যে একটি সাধারণ "অদলবদল" করতে একটি ফেড থ্রু ব্যবহার করব৷

কোনও অতিরিক্ত কোড যোগ করার আগে, অ্যাপটি চালানোর চেষ্টা করুন, একটি ইমেলে আলতো চাপুন এবং ইমেল ভিউ খুলুন। FAB আইকন পরিবর্তন ছাড়াই পরিবর্তন করা উচিত।

আগে

d8e3afa0447cfc20.gif

কোডল্যাবের বাকি অংশের জন্য আমরা home.dart এ কাজ করব, তাই অ্যানিমেশন প্যাকেজের জন্য আমদানি যোগ করার বিষয়ে চিন্তা করবেন না যেহেতু আমরা ইতিমধ্যেই home.dart এর জন্য 2 ধাপে ফিরে এসেছি।

আমরা যেভাবে পরবর্তী কয়েকটি ট্রানজিশন কনফিগার করব তা খুব একই রকম হবে, যেহেতু তারা সবাই একটি পুনঃব্যবহারযোগ্য ক্লাস ব্যবহার করবে, _FadeThroughTransitionSwitcher

home.dart এ আসুন _ReplyFabState অধীনে নিম্নলিখিত স্নিপেট যোগ করি:

home.dart

// 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 দিয়ে মোড়ানো যাক:

home.dart

// 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 আইকনটি বিবর্ণ হয়ে যায় এবং স্কেল আউট হয়ে যায় যখন নতুনটি বিবর্ণ হয়ে যায় এবং স্কেল হয়ে যায়।

পরে

c55bacd9a144ec69.gif

10. অদৃশ্য হয়ে যাওয়া মেলবক্স শিরোনামের মধ্যে পরিবর্তনের মাধ্যমে ফেড যোগ করুন

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

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

আগে

59eb57a6c71725c0.gif

এই কোডল্যাবের বাকিটা দ্রুত হবে কারণ আমরা ইতিমধ্যেই আমাদের শেষ ধাপে আমাদের _FadeThroughTransitionSwitcher এ বেশিরভাগ কাজ করে ফেলেছি।

এখন, আমাদের স্থানান্তর যোগ করতে home.dart এ আমাদের _AnimatedBottomAppBar ক্লাসে যাওয়া যাক। আমরা আমাদের শেষ ধাপ থেকে _FadeThroughTransitionSwitcher পুনরায় ব্যবহার করব, এবং আমাদের onMailView শর্তসাপেক্ষে মোড়ানো হবে, যা হয় একটি খালি SizedBox ফেরত দেয়, অথবা একটি মেলবক্স শিরোনাম যা নীচের ড্রয়ারের সাথে সিঙ্কে বিবর্ণ হয়:

home.dart

...
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,
                   ),
             );
           },
         ),
       ),
),

এটাই, আমরা এই পদক্ষেপটি সম্পন্ন করেছি!

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

পরে

3f1a3db01a481124.gif

11. নিচের অ্যাপ বার অ্যাকশনের মধ্যে পরিবর্তনের মাধ্যমে ফেইড যোগ করুন

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

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

আগে

5f662eac19fce3ed.gif

শেষ ধাপের মতো, আমরা আবার আমাদের _FadeThroughTransitionSwitcher ব্যবহার করব। কাঙ্খিত রূপান্তরটি অর্জন করতে আমাদের _BottomAppBarActionItems শ্রেণীর সংজ্ঞাতে যান এবং একটি _FadeThroughTransitionSwitcher দিয়ে আমাদের build() ফাংশনের রিটার্ন উইজেটটি মোড়ানো করুন:

home.dart

// 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
...

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

পরে

cff0fa2afa1c5a7f.gif

12. অভিনন্দন!

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

d5637de49eb64d8a.gif

পরবর্তী পদক্ষেপ

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

উপাদান গতি চেষ্টা করার জন্য ধন্যবাদ. আমরা আশা করি আপনি এই কোডল্যাব উপভোগ করেছেন!

আমি যুক্তিসঙ্গত সময় এবং প্রচেষ্টার সাথে এই কোডল্যাবটি সম্পূর্ণ করতে সক্ষম হয়েছি

দৃঢ়ভাবে একমত একমত নিরপেক্ষ অসম্মতি দৃঢ়ভাবে অসম্মতি

আমি ভবিষ্যতে মেটেরিয়াল মোশন সিস্টেম ব্যবহার চালিয়ে যেতে চাই

দৃঢ়ভাবে একমত একমত নিরপেক্ষ অসম্মতি দৃঢ়ভাবে অসম্মতি

মেটেরিয়াল ফ্লাটার লাইব্রেরি দ্বারা প্রদত্ত উইজেটগুলি কীভাবে ব্যবহার করতে হয় সে সম্পর্কে আরও ডেমোর জন্য, পাশাপাশি ফ্লাটার ফ্রেমওয়ার্ক ফ্লাটার গ্যালারিতে যেতে ভুলবেন না।

46ba920f17198998.png

6ae8ae284bf4f9fa.png