Flutter के लिए मटीरियल मोशन इस्तेमाल करके खूबसूरत ट्रांज़िशन बनाना

1. परिचय

मटीरियल डिज़ाइन एक ऐसा सिस्टम है जो अच्छे और आकर्षक डिजिटल प्रॉडक्ट बनाता है. प्रॉडक्ट टीमें, स्टाइल, ब्रैंडिंग, इंटरैक्शन, और मोशन को सिद्धांतों और कॉम्पोनेंट के एक जैसे सेट में जोड़कर, डिज़ाइन की अपनी सबसे बड़ी क्षमता को साकार कर सकती हैं.

logo_components_color_2x_web_96dp.png

मटीरियल कॉम्पोनेंट (एमडीसी), मटीरियल डिज़ाइन लागू करने में डेवलपर की मदद करते हैं. Google के इंजीनियरों और UX डिज़ाइनर की टीम ने बनाया है. एमडीसी में दर्जनों खूबसूरत और काम करने वाले यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट हैं. यह Android, iOS, वेब, और Flutter.material.io/प्रॉडक्ट के लिए उपलब्ध है

Flutter के लिए Material का मोशन सिस्टम क्या है?

Flutter के लिए मटीरियल मोशन सिस्टम, ऐनिमेशन पैकेज में ट्रांज़िशन पैटर्न का एक सेट है. यह मटीरियल डिज़ाइन से जुड़े दिशा-निर्देश के मुताबिक, ऐप्लिकेशन को समझने और इस्तेमाल करने में उपयोगकर्ताओं की मदद कर सकता है.

Material के चार मुख्य ट्रांज़िशन पैटर्न इस तरह हैं:

  • कंटेनर ट्रांसफ़ॉर्म: यह उन यूज़र इंटरफ़ेस (यूआई) एलिमेंट के बीच ट्रांज़िशन करता है जिनमें कंटेनर शामिल है. यह एक एलिमेंट को दूसरे एलिमेंट में आसानी से ट्रांसफ़ॉर्म करके, दो अलग-अलग यूज़र इंटरफ़ेस (यूआई) एलिमेंट के बीच, दिखने वाला कनेक्शन बनाता है.

11807bdf36c66657.gif

  • शेयर किया गया ऐक्सिस: यह उन यूज़र इंटरफ़ेस (यूआई) एलिमेंट के बीच ट्रांज़िशन होता है जो जगह या नेविगेशन से जुड़े होते हैं. एलिमेंट के बीच संबंध को बेहतर बनाने के लिए, x, y या z ऐक्सिस पर शेयर किए गए ट्रांसफ़ॉर्मेशन का इस्तेमाल किया जाता है.

71218f390abae07e.gif

  • फ़ेड थ्रू: यह ट्रांज़िशन, उन यूज़र इंटरफ़ेस (यूआई) एलिमेंट के बीच होता है जिनके बीच बेहतर तालमेल नहीं होता. इसमें, आने वाले एलिमेंट के स्केल के साथ, फ़ेड आउट और फ़ेड इन का क्रमिक तरीके से इस्तेमाल किया जाता है.

385ba37b8da68969.gif

  • फ़ेड: इसका इस्तेमाल ऐसे यूज़र इंटरफ़ेस (यूआई) एलिमेंट के लिए किया जाता है जो स्क्रीन की सीमाओं के अंदर से जुड़ते हैं या बाहर निकलते हैं.

cfc40fd6e27753b6.gif

ऐनिमेशन पैकेज में, इन पैटर्न के लिए ट्रांज़िशन विजेट उपलब्ध हैं. ये विजेट, Flutter ऐनिमेशन लाइब्रेरी (flutter/animation.dart) और Flutter मटीरियल लाइब्रेरी (flutter/material.dart) दोनों के ऊपर बनाए गए हैं:

इस कोडलैब में, आपको Flutter फ़्रेमवर्क और Material लाइब्रेरी पर बनाए गए Material ट्रांज़िशन का इस्तेमाल करना होगा. इसका मतलब है कि आपको विजेट का इस्तेमाल करना होगा. :)

आपको क्या बनाना होगा

इस कोडलैब में, Dart का इस्तेमाल करके Reply नाम के Flutter ईमेल ऐप्लिकेशन के उदाहरण में कुछ ट्रांज़िशन बनाने का तरीका बताया गया है. इससे आपको यह जानने में मदद मिलेगी कि ऐनिमेशन पैकेज के ट्रांज़िशन का इस्तेमाल करके, अपने ऐप्लिकेशन को पसंद के मुताबिक कैसे बनाया जा सकता है.

आपको Reply ऐप्लिकेशन का स्टार्टर कोड दिया जाएगा. साथ ही, आपको ऐप्लिकेशन में ये Material ट्रांज़िशन शामिल करने होंगे. इन्हें पूरा किए गए कोडलैब के GIF में देखा जा सकता है:

  • कंटेनर ट्रांसफ़ॉर्म का इस्तेमाल, ईमेल सूची से ईमेल की ज़्यादा जानकारी वाले पेज पर किया जाता है
  • ईमेल पेज लिखने के लिए, एफ़एबी से कंटेनर ट्रांसफ़ॉर्म का ट्रांज़िशन
  • खोज आइकॉन से खोज व्यू पेज पर शेयर किए गए ज़ेड-ऐक्सिस ट्रांज़िशन
  • मेलबॉक्स पेजों के बीच फ़ेड थ्रू ट्रांज़िशन
  • 'लिखें' और 'जवाब दें' फ़्लोटिंग ऐक्शन बटन के बीच फ़ेड थ्रू ट्रांज़िशन
  • गायब होने वाले मेलबॉक्स के शीर्षक के बीच फ़ेड थ्रू ट्रांज़िशन
  • ऐप्लिकेशन बार पर नीचे दी गई कार्रवाइयों के बीच ट्रांज़िशन के लिए फ़ेड थ्रू

b26fe84fed12d17d.gif

आपको इन चीज़ों की ज़रूरत होगी

  • Flutter डेवलपमेंट और Dart की बुनियादी जानकारी
  • कोड एडिटर
  • Android/iOS एमुलेटर या डिवाइस
  • सैंपल कोड (अगला चरण देखें)

Flutter ऐप्लिकेशन बनाने के अपने अनुभव को क्या रेटिंग देंगे?

नौसिखिया मध्यम प्रवीण

आपको इस कोडलैब से क्या सीखना है?

मैं इस विषय के बारे में नहीं जानता/जानती. मुझे इसकी खास जानकारी चाहिए. मुझे इस विषय के बारे में कुछ पता है, लेकिन मुझे इस बारे में फिर से जानना है. मुझे अपने प्रोजेक्ट में इस्तेमाल करने के लिए, उदाहरण के तौर पर दिया गया कोड चाहिए. मुझे किसी खास चीज़ के बारे में जानकारी चाहिए.

2. Flutter डेवलपमेंट एनवायरमेंट को सेट अप करें

इस लैब को पूरा करने के लिए, आपके पास दो सॉफ़्टवेयर होने चाहिए— Flutter SDK टूल और एडिटर.

इनमें से किसी भी डिवाइस का इस्तेमाल करके, कोडलैब चलाया जा सकता है:

  • आपके कंप्यूटर से कनेक्ट किया गया Android या iOS डिवाइस होना चाहिए और वह डेवलपर मोड पर सेट होना चाहिए.
  • iOS सिम्युलेटर (इसके लिए, Xcode टूल इंस्टॉल करने की ज़रूरत है).
  • Android Emulator (Android Studio में सेटअप करना ज़रूरी है).
  • ब्राउज़र (डीबग करने के लिए Chrome ज़रूरी है).
  • Windows, Linux या macOS डेस्कटॉप ऐप्लिकेशन के तौर पर. आपको उस प्लैटफ़ॉर्म पर ऐप्लिकेशन बनाना होगा जिस पर आपको उसे डिप्लॉय करना है. इसलिए, अगर आपको Windows डेस्कटॉप ऐप्लिकेशन बनाना है, तो आपको सही बिल्ड चेन ऐक्सेस करने के लिए, Windows पर डेवलप करना होगा. ऑपरेटिंग सिस्टम के हिसाब से कुछ ज़रूरी शर्तें होती हैं. इनके बारे में ज़्यादा जानकारी docs.flutter.dev/desktop पर दी गई है.

3. कोडलैब का स्टार्टर ऐप्लिकेशन डाउनलोड करना

पहला विकल्प: 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. अपने चुने हुए एडिटर के लिए, शुरू करें: टेस्ट ड्राइव में "ऐप्लिकेशन चलाएं" के निर्देशों का पालन करें.

हो गया! जवाब दें सुविधा के होम पेज के लिए स्टार्टर कोड, आपके डिवाइस/एम्युलेटर पर चलना चाहिए. आपको इनबॉक्स दिखेगा, जिसमें ईमेल की सूची होगी.

होम पेज पर जवाब दें

ज़रूरी नहीं: डिवाइस के ऐनिमेशन की स्पीड कम करना

इस कोडलैब में तेज़ और बेहतर ट्रांज़िशन शामिल हैं. इसलिए, ट्रांज़िशन लागू करते समय, डिवाइस के ऐनिमेशन को धीमा करके, ट्रांज़िशन की बेहतर जानकारी देखी जा सकती है. ऐसा इन-ऐप्लिकेशन सेटिंग से किया जा सकता है. इसे सबसे नीचे वाला पैनल खुले होने पर, सेटिंग आइकॉन पर टैप करके ऐक्सेस किया जा सकता है. चिंता न करें, डिवाइस के ऐनिमेशन को धीमा करने के इस तरीके से, जवाब देने वाले ऐप्लिकेशन के बाहर डिवाइस पर मौजूद ऐनिमेशन पर कोई असर नहीं पड़ेगा.

d23a7bfacffac509.gif

ज़रूरी नहीं: गहरे रंग वाला मोड

अगर जवाब दें की चमकदार थीम आपकी आंखों को दुख दे रही है, तो और आगे न देखें. इसमें एक ऐसी इन-ऐप्लिकेशन सेटिंग भी शामिल है जिससे आपको ऐप्लिकेशन की थीम को गहरे रंग वाले मोड में बदलने का विकल्प मिलता है. इससे, आपकी आंखों के हिसाब से यह सेटिंग बेहतर तरीके से काम कर पाती है. सबसे नीचे मौजूद ड्रॉअर खुला होने पर, सेटिंग आइकॉन पर टैप करके इस सेटिंग को ऐक्सेस किया जा सकता है.

87618d8418eee19e.gif

4. सैंपल ऐप्लिकेशन कोड के बारे में जानें

आइए कोड को देखें. हमने एक ऐप्लिकेशन उपलब्ध कराया है, जो ऐप्लिकेशन की अलग-अलग स्क्रीन के बीच ट्रांज़िशन करने के लिए, ऐनिमेशन पैकेज का इस्तेमाल करता है.

  • होम पेज: चुना गया मेलबॉक्स दिखाता है
  • InboxPage: ईमेल की सूची दिखाता है
  • MailPreviewCard: यह किसी ईमेल की झलक दिखाता है
  • MailViewPage: एक पूरा ईमेल दिखाता है
  • ComposePage: इसकी मदद से नया ईमेल लिखा जा सकता है
  • SearchPage: खोज व्यू दिखाता है

router.dart

सबसे पहले, यह समझने के लिए कि ऐप्लिकेशन का रूट नेविगेशन कैसे सेटअप किया जाता है, 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, ईमेल की सूची दिखाता है. यह सूची इस बात पर निर्भर करती है कि हमारे ऐप्लिकेशन में मौजूदा मेलबॉक्स की स्थिति क्या है. जब भी हमारे ऐप्लिकेशन की स्थिति की currentlySelectedInbox प्रॉपर्टी में कोई बदलाव होता है, तो स्टैक के सबसे ऊपर सही InboxPage के साथ नेविगेटर को फिर से बनाया जाता है.

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

आखिर में, इस्तेमाल किए जा रहे नेविगेशन रूटिंग का उदाहरण देखने के लिए, home.dart को lib डायरेक्ट्री में खोलें. 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. ईमेल सूची से ईमेल की ज़्यादा जानकारी वाले पेज पर कंटेनर ट्रांसफ़ॉर्म ट्रांज़िशन जोड़ना

शुरू करने के लिए, आपको किसी ईमेल पर क्लिक करते समय ट्रांज़िशन जोड़ना होगा. नेविगेशन में इस बदलाव के लिए, कंटेनर ट्रांसफ़ॉर्म पैटर्न का इस्तेमाल करना सबसे सही रहेगा. इस पैटर्न को उन यूज़र इंटरफ़ेस (यूआई) एलिमेंट के बीच ट्रांज़िशन के लिए डिज़ाइन किया गया है जिनमें कंटेनर शामिल होता है. इस पैटर्न से दो यूज़र इंटरफ़ेस (यूआई) एलिमेंट के बीच, दिखने वाला कनेक्शन बनाने में मदद मिलती है.

किसी भी कोड को जोड़ने से पहले, जवाब दें ऐप्लिकेशन को चलाकर और ईमेल पर क्लिक करके देखें. इसे बस जंप-कट किया जाना चाहिए, जिसका मतलब है कि स्क्रीन को बिना किसी ट्रांज़िशन के बदल दिया गया है:

पहले

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() फ़ंक्शन से Material विजेट को अपने नए _OpenContainerWrapper के साथ रैप करेंगे:

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 की कलर प्रॉपर्टी से, उसमें मौजूद कंटेनर का रंग तय होता है. इसलिए, हम Material और Inkwell विजेट हटा सकते हैं. इससे मिलने वाला कोड कुछ ऐसा दिखता है:

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. ईमेल पेज लिखने के लिए, एफ़एबी से कंटेनर ट्रांसफ़ॉर्म का ट्रांज़िशन जोड़ें

चलिए, कंटेनर ट्रांसफ़ॉर्मेशन के साथ आगे बढ़ते हैं और फ़्लोटिंग ऐक्शन बटन से ComposePage में ट्रांज़िशन जोड़ते हैं. इससे, उपयोगकर्ता को फ़्लोटिंग ऐक्शन बटन को बड़ा करके, नया ईमेल लिखने की सुविधा मिलती है. सबसे पहले, ऐप्लिकेशन को फिर से चलाएं और एफ़एबी पर क्लिक करके देखें कि ईमेल लिखने वाली स्क्रीन को लॉन्च करते समय कोई ट्रांज़िशन नहीं हो रहा.

पहले

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 विजेट, closedColor के साथ closedBuilder से मिले विजेट के रंग को हैंडल करता है. हम अपने InkWell विजेट के onTap में से Navigator.push() कॉल को हटा देंगे और उसे OpenContainer विजेट के closedBuilder से मिले openContainer() Callback से बदल देंगे, क्योंकि अब 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);

इस चरण के लिए बस इतना ही! फ़्लोटिंग ऐक्शन बटन से कॉम्पोज़ स्क्रीन पर जाने का ट्रांज़िशन ऐसा होना चाहिए:

इसके बाद

5c7ad1b4b40f9f0c.gif

7. शेयर किए गए Z-ऐक्सिस से ट्रांज़िशन को खोज आइकॉन से खोज व्यू पेज पर जोड़ें

इस चरण में, हम खोज आइकॉन से फ़ुल स्क्रीन में खोज व्यू में ट्रांज़िशन जोड़ेंगे. इस नेविगेशन में कोई पर्सिस्टेंट कंटेनर शामिल नहीं है. इसलिए, हम दोनों स्क्रीन के बीच के स्पेस के संबंध को बेहतर बनाने के लिए, शेयर किए गए ज़ेड-ऐक्सिस ट्रांज़िशन का इस्तेमाल कर सकते हैं. साथ ही, ऐप्लिकेशन की हैरारकी में एक लेवल ऊपर जाने का संकेत दे सकते हैं.

अतिरिक्त कोड जोड़ने से पहले, ऐप्लिकेशन चलाएं और स्क्रीन के नीचे दाएं कोने में खोज आइकॉन पर टैप करें. इससे बिना किसी संक्रमण के खोज दृश्य स्क्रीन आ जाएगी.

इससे पहले

df7683a8ad7b920e.gif

शुरू करने के लिए, router.dart फ़ाइल पर जाएं. ReplySearchPath क्लास की परिभाषा के बाद, यह स्निपेट जोड़ें:

router.dart

// 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 से रैप करते हैं:

router.dart

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 के बजाय HomePage को SharedAxisTransitionWrapper के साथ रैप करें:

router.dart

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. 'लिखें' और 'जवाब दें' फ़्लोटिंग ऐक्शन बटन के बीच फ़ेड-थ्रू ट्रांज़िशन जोड़ना

इस चरण में, हम अलग-अलग फ़्लोटिंग ऐक्शन बटन (एफ़एबी) आइकॉन के बीच ट्रांज़िशन जोड़ेंगे. हम किसी जगह या हैरारकी के संबंध पर ज़ोर नहीं देना चाहते. इसलिए, हम एफ़एबी में मौजूद आइकॉन को आसानी से "स्वैप" करने के लिए, फ़ेड थ्रू का इस्तेमाल करेंगे.

कोई और कोड जोड़ने से पहले, ऐप्लिकेशन को चलाकर, किसी ईमेल पर टैप करके ईमेल व्यू खोलें. फ़्लाइंग ऐरो बटन का आइकॉन, ट्रांज़िशन के बिना बदलना चाहिए.

पहले

d8e3afa0447cfc20.gif

हम कोडलैब के बाकी बचे दिनों में, home.dart में काम करेंगे. इसलिए, ऐनिमेशन पैकेज के लिए इंपोर्ट करने की चिंता न करें, क्योंकि दूसरे चरण में हमने पहले ही home.dart के लिए ऐसा किया था.

अगले कुछ ट्रांज़िशन को कॉन्फ़िगर करने का तरीका काफ़ी हद तक एक जैसा होगा, क्योंकि इन सभी में फिर से इस्तेमाल की जा सकने वाली क्लास, _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 भी बनाते हैं और उसे किसी एक आइकॉन को असाइन करते हैं.

अब, इस चरण में आपके पास पूरी तरह से ऐनिमेशन वाला, कॉन्टेक्स्ट के हिसाब से फ़्लोटिंग ऐक्शन बटन होना चाहिए. ईमेल व्यू में जाने से पुराना एफ़एबी आइकॉन धुंधला हो जाएगा और स्केल आउट हो जाएगा. साथ ही, नया एफ़एबी आइकॉन फ़ेड हो जाएगा और बड़ा हो जाएगा.

इसके बाद

c55bacd9a144ec69.gif

10. गायब हो रहे मेलबॉक्स टाइटल के बीच फ़ेड थ्रू ट्रांज़िशन जोड़ें

इस चरण में, हम ईमेल दृश्य में दिखाई देने और दिखाई न देने वाली स्थिति के बीच मेलबॉक्स शीर्षक में फ़ेड थ्रू ट्रांज़िशन जोड़ेंगे. हम किसी जगह या क्रम के हिसाब से संबंध पर ज़ोर नहीं देना चाहते. इसलिए, हम मेलबॉक्स के टाइटल वाले Text विजेट और खाली SizedBox के बीच आसानी से "स्वाप" करने के लिए, फ़ेड-थ्रू का इस्तेमाल करेंगे.

कोई और कोड जोड़ने से पहले, ऐप्लिकेशन को चलाकर, किसी ईमेल पर टैप करके ईमेल व्यू खोलें. मेलबॉक्स का टाइटल, ट्रांज़िशन के बिना गायब हो जाना चाहिए.

पहले

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 क्लास डेफ़िनिशन पर जाएं और हमारे build() फ़ंक्शन के रिटर्न विजेट को _FadeThroughTransitionSwitcher से रैप करें:

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 से भी कम लाइनों वाले Dart कोड का इस्तेमाल करके, किसी मौजूदा ऐप्लिकेशन में शानदार ट्रांज़िशन बनाए जा सकते हैं. ये ट्रांज़िशन, Material Design के दिशा-निर्देशों के मुताबिक होते हैं. साथ ही, ये सभी डिवाइसों पर एक जैसे दिखते हैं और एक जैसे काम करते हैं.

d5637de49eb64d8a.gif

अगले चरण

मटीरियल मोशन सिस्टम के बारे में ज़्यादा जानकारी के लिए, दिशा-निर्देश और पूरे डेवलपर दस्तावेज़ देखना न भूलें. साथ ही, अपने ऐप्लिकेशन में कुछ मटीरियल ट्रांज़िशन जोड़कर देखें!

मटीरियल मोशन आज़माने के लिए धन्यवाद. हमें उम्मीद है कि आपको यह कोडलैब पसंद आया होगा!

मैंने सही समय और मेहनत में इस कोडलैब को पूरा कर लिया

पूरी तरह सहमत सहमत न सहमत हूं असहमत हूं पूरी तरह असहमत

मुझे आने वाले समय में, Material मोशन सिस्टम का इस्तेमाल जारी रखना है

पूरी तरह सहमत सहमत न तो सहमत, न ही असहमत असहमति है पूरी तरह असहमति है

मटीरियल फ़्लटर लाइब्रेरी से मिले विजेट और Flutter फ़्रेमवर्क के इस्तेमाल से जुड़े ज़्यादा डेमो के लिए, Flutter Gallery में ज़रूर जाएं.

46ba920f17198998.png

6ae8ae284bf4f9fa.png