एक कंपित एनीमेशन में अनुक्रमिक या ओवरलैपिंग एनिमेशन होते हैं। एनीमेशन पूरी तरह से अनुक्रमिक हो सकता है, जिसमें एक के बाद एक बदलाव होते हैं, या यह आंशिक रूप से या पूरी तरह से ओवरलैप हो सकता है। जब एनीमेशन अनुक्रमिक होता है, तो तत्वों को प्रत्येक तत्व के प्रारंभ समय के बीच थोड़ी देरी के साथ क्रमिक रूप से एनिमेटेड किया जाता है। यह एक कैस्केडिंग या लहर प्रभाव बनाता है, जहां एनीमेशन एक साथ सभी तत्वों के बजाय चरणों में चलता हुआ प्रतीत होता है। स्टैगर्ड एनिमेशन को माइक्रो-इंटरैक्शन का एक प्रकार माना जाता है क्योंकि वे उपयोगकर्ता को इंटरफ़ेस के माध्यम से मार्गदर्शन करने वाले सूक्ष्म, इंटरैक्टिव फ़ीडबैक प्रदान करके उपयोगकर्ता अनुभव को बढ़ाते हैं। फ़्लटर में, आप अंतर्निहित या स्पष्ट एनीमेशन का उपयोग करके सूक्ष्म एनिमेशन तैयार करके माइक्रो-इंटरैक्शन बना सकते हैं। संदर्भ के लिए, निहित एनिमेशन को सरल और उपयोग में आसान बनाने के लिए डिज़ाइन किया गया है क्योंकि एनिमेशन विवरण को सारगर्भित किया जाता है जबकि स्पष्ट एनिमेशन जटिल एनिमेशन के लिए अधिक उपयुक्त होते हैं क्योंकि वे एनिमेशन प्रक्रिया पर पूर्ण नियंत्रण प्रदान करते हैं। इसका उपयोग विशेष रूप से तब किया जाता है जब आपको एनिमेशन पर अधिक बारीक नियंत्रण की आवश्यकता होती है। इस लेख में, हम माइक्रो-इंटरैक्शन की अवधारणा पर गहराई से चर्चा करेंगे, फिर एक माइक्रो-इंटरैक्शन उपयोग मामले के लिए, हम एक स्तंभित एनीमेशन बनाने के लिए स्पष्ट एनीमेशन का उपयोग करेंगे जो एक कॉलम विजेट में निहित बच्चों को एनिमेट करता है। माइक्रो-इंटरैक्शन की अवधारणा क्या है? बेहतरीन उत्पाद वे उत्पाद हैं जो सुविधाओं और विवरण दोनों पर अच्छी तरह से काम करते हैं। सुविधाएँ लोगों को आपके उत्पादों तक लाती हैं, लेकिन विवरण उन्हें बनाए रखते हैं। ये विवरण ऐसी चीजें हैं जो आपके ऐप को दूसरों से अलग बनाती हैं। माइक्रो-इंटरैक्शन के साथ, आप अपने उपयोगकर्ताओं को सुखद प्रतिक्रिया देकर ये विवरण बना सकते हैं। माइक्रो-इंटरैक्शन की अवधारणा इस विचार पर आधारित है कि छोटे विवरण समग्र उपयोगकर्ता अनुभव पर बड़ा प्रभाव डाल सकते हैं। माइक्रो-इंटरैक्शन का उपयोग फीडबैक या किसी कार्रवाई के परिणाम को संप्रेषित करने जैसे आवश्यक कार्यों को पूरा करने के लिए किया जा सकता है। माइक्रो-इंटरैक्शन के उदाहरणों में शामिल हैं: बटन एनिमेशन: बटन पर माउस घुमाने या दबाने पर उसका रंग या आकार बदल जाता है। लोडिंग संकेतक: एनिमेशन जो उपयोगकर्ता को संकेत देते हैं कि कोई प्रक्रिया प्रगति पर है। स्वाइप जेस्चर: एनिमेशन जो स्वाइप जेस्चर पर प्रतिक्रिया देते हैं। नेविगेशन संक्रमण: स्क्रीन के बीच संक्रमण करते समय सहज एनिमेशन। वास्तविक जीवन के अनुप्रयोगों में सूक्ष्म-अंतःक्रियाएँ नीचे, हम माइक्रो-इंटरैक्शन के वास्तविक जीवन के अनुप्रयोगों को देख सकते हैं, ये सूक्ष्म एनिमेशन उपयोगकर्ता अनुभव को बढ़ाने के लिए फ़्लटर में बनाए गए हैं। इन ऐप्स के लिए डिज़ाइन संदर्भ ड्रिब्बल से प्राप्त किए गए थे फ़्लटर में स्टैगर्ड एनीमेशन कैसे बनाएं इस उदाहरण में, हम एक ऐसा कंपित एनीमेशन बनाएंगे जो पेज स्वाइप करने पर कॉलम विजेट में बच्चों को एनिमेट करता है। इसे स्पष्ट एनीमेशन दृष्टिकोण का उपयोग करके बनाया जाएगा क्योंकि इस मामले में, हमें इस बात पर पूरा नियंत्रण रखना होगा कि हम एनीमेशन को कैसे चलाना चाहते हैं। जब हम पूरा कर लेंगे तो एनीमेशन कुछ इस तरह दिखेगा 👇🏽 शर्त इस ट्यूटोरियल का अधिकतम लाभ उठाने के लिए आपके पास निम्नलिखित चीजें होनी चाहिए: फ़्लटर में एनिमेशन कैसे बनाए जाते हैं, इसकी बुनियादी समझ फ़्लटर और डार्ट के मूल सिद्धांतों की अच्छी समझ एक कोड संपादक, या तो VScode या Android Studio एक एमुलेटर या डिवाइस जिस पर निर्माण किया जा सके एक बार जब आप परियोजना की सभी पूर्व-आवश्यकताओं की जांच कर लें, तो चलिए इसमें आगे बढ़ते हैं। सबसे पहले, हम मुख्य स्क्रीन बनाएंगे जिसमें ये दो पेज होंगे। ये दोनों पेज एक पेजव्यू विजेट में लिपटे होंगे जो नियंत्रित करेगा कि स्वाइप करने पर कौन सा पेज प्रदर्शित होगा। साथ ही, मुख्य स्क्रीन के निचले भाग में, हमारे पास एक संकेतक है जो हमें वह पेज दिखाता है जिस पर हम वर्तमान में हैं। class MainScreen extends StatefulWidget { const MainScreen({super.key}); @override State<MainScreen> createState() => _MainScreenState(); } class _MainScreenState extends State<MainScreen>{ final controller = PageController(keepPage: true); @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: PageView( controller: controller, children: [ Page1(pageController: controller,), Page2(pageController: controller,), ], ), ), bottomNavigationBar: Container( alignment: Alignment.topCenter, padding: const EdgeInsets.only(top: 10), height: 30, child: SmoothPageIndicator( controller: controller, count: 2, effect: const JumpingDotEffect( dotHeight: 10, dotWidth: 10, activeDotColor: Colors.grey, dotColor: Colors.black12, ), ), ) ); } } ऊपर दिए गए कोड स्निपेट में इस्तेमाल किया गया पर पाया जा सकता है। यहाँ, उपयोग वर्तमान पृष्ठ को दृश्य में दिखाने के लिए किया जाता है। आप इस पैकेज को अपने में इस तरह जोड़ सकते हैं 👇🏽 SmoothPageIndicator pub.dev SmoothPageIndicator pubspec.yaml dependencies: flutter: sdk: flutter smooth_page_indicator: ^1.1.0 दो पेजों में, हमारे पास कई खाली कार्ड विजेट के साथ एक कॉलम विजेट होगा। इन खाली कार्ड विजेट का उपयोग कॉलम को पॉप्युलेट करने के लिए किया जाएगा ताकि हम स्टैगर्ड एनीमेशन को पूरी तरह से देख सकें और उसकी सराहना कर सकें। हम खाली कार्ड विजेट को एक पुनः उपयोग करने योग्य घटक के रूप में बनाएंगे ताकि हमें इसे हर जगह पर स्क्रैच से न बनाना पड़े। class EmptyCard extends StatelessWidget { const EmptyCard({super.key, required this.width, required this.height}); final double width; final double height; @override Widget build(BuildContext context) { return Container( height: height, width: width, decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(10)), color: Colors.blue.shade200, boxShadow: const [ BoxShadow( color: Colors.black12, blurRadius: 4, offset: Offset(0,4), ) ] ), ); } } इन सभी बॉयलरप्लेट कोड को पूरा करने के बाद, अब हम एनीमेशन बनाना शुरू करेंगे। सबसे पहले, हम एक नया स्टेटफुल विजेट बनाएंगे जिसे हम कहेंगे। इसमें एनीमेशन को कैसे चलाया जाए, इसे नियंत्रित करने के लिए कई पैरामीटर होंगे। AnimateWidget class AnimateWidget extends StatefulWidget { const AnimateWidget({super.key, required this.duration, required this.position, required this.horizontalOffset, required this.child, required this.controller, }); final Duration duration; final int position; final double? horizontalOffset; final Widget child; final PageController controller; @override State<AnimateWidget> createState() => _AnimateWidgetState(); } जैसा कि ऊपर दिए गए स्निपेट में देखा गया है, के पैरामीटर्स के साथ, हम सफलतापूर्वक नियंत्रित कर सकते हैं: AnimateWidget एनीमेशन की अवधि. , जिसके कारण पृष्ठ स्वाइप किए जाने पर एनीमेशन ट्रिगर हो जाता है। pageController एनिमेटेड तत्व की क्षैतिज ऑफसेट की मात्रा. इसके बाद, में, हम निम्नलिखित को परिभाषित करेंगे: AnimateWiget : एनीमेशन अनुक्रम को नियंत्रित करने के लिए उपयोग किया जाता है। AnimationController वर्तमान पृष्ठ: वर्तमान पृष्ठ डेटा रखने के लिए उपयोग किया जाएगा. टाइमर: कुछ देरी के बाद एनीमेशन को ट्रिगर करने के लिए उपयोग किया जाएगा; यह वही है जो कंपित एनीमेशन कैस्केडिंग प्रभाव लाएगा। class _AnimateWidgetState extends State<AnimateWidget> with AutomaticKeepAliveClientMixin, SingleTickerProviderStateMixin{ @override bool get wantKeepAlive => true; late AnimationController animationController; int currentPage = 0; Timer? _timer; @override void initState() { super.initState(); animationController = AnimationController(vsync: this, duration: widget.duration); _timer = Timer(getDelay(), animationController.forward); widget.controller.addListener(() { currentPage = widget.controller.page!.round(); if(currentPage == widget.controller.page){ _timer = Timer(getDelay(), animationController.forward); } }); } @override void dispose() { _timer?.cancel(); animationController.dispose(); super.dispose(); } Duration getDelay(){ var delayInMilliSec = widget.duration.inMilliseconds ~/ 6; int getStaggeredListDuration(){ return widget.position * delayInMilliSec; } return Duration(milliseconds: getStaggeredListDuration()); } उपरोक्त कोड स्निपेट को तोड़कर देखने पर आप देखेंगे कि: हमने एनीमेशन अनुक्रम को नियंत्रित करने के लिए उपयोग किया, इस वजह से, हमने पेश किया। AnimationController SingleTickerProviderStateMixin विधि में, हमने आरंभीकृत किया, फिर पेज प्रविष्टि और पेज स्वाइप पर का उपयोग करके एनीमेशन को ट्रिगर किया। init state AnimationController animationController.forward हमने विलंब के आधार पर एनीमेशन के ट्रिगरिंग को नियंत्रित करने के लिए टाइमर का उपयोग किया। विधि में, हमने संसाधनों को साफ किया। dispose हमने विजेट की स्थिति को सुरक्षित रखने के लिए का उपयोग किया। यह के निपटान को रोकने के लिए है, जब कोई पेज स्वाइप किया जाता है और दिखाई नहीं देता है। AutomaticKeepAliveClientMixin AnimationController फ़ंक्शन में, हमने प्रत्येक तत्व के लिए एनीमेशन ट्रिगर होने से पहले की देरी की गणना की। इसे प्राप्त करने के लिए, हमने मिलीसेकंड में अवधि को 6 से विभाजित किया और परिणामों का अनुमान लगाया, फिर इसे स्थिति से गुणा किया। यह तत्व की स्थिति (इस मामले में, सूचकांक) है। getDelay बिल्ड विधि में, हम एक लौटाते हैं। इस एनिमेटेड बिल्डर में, हम नामक एक विजेट फ़ंक्शन लौटाएंगे जो एक विजेट लौटाता है। फ़ंक्शन में, हमारे पास फ़ंक्शन है। AnimatedBuilder _slideAnimation Transform.translate _slideAnimation offsetAnimation फ़ंक्शन एनिमेशन प्रॉपर्टी लौटाता है जिसका उपयोग विजेट में किया जाता है। विजेट एनिमेशन से मान का उपयोग करके चाइल्ड विजेट को एनिमेट करता है। offsetAnimation Transform.translate Transform.translate @override Widget build(BuildContext context) { super.build(context); return AnimatedBuilder( animation: animationController, builder: (context, child){ return _slideAnimation(animationController); } ); } Widget _slideAnimation(Animation<double> animationController){ Animation<double> offsetAnimation(double offset, Animation<double> animationController) { return Tween<double>(begin: offset, end: 0.0).animate( CurvedAnimation( parent: animationController, curve: const Interval(0.0, 1.0, curve: Curves.ease), ), ); } return Transform.translate( offset: Offset( widget.horizontalOffset == 0.0 ? 0.0 : offsetAnimation(widget.horizontalOffset!, animationController).value, 0.0, ), child: widget.child, ); } यह क्लास का पूरा कोड है 👇🏽 AnimateWidget class AnimateWidget extends StatefulWidget { const AnimateWidget({super.key, required this.duration, required this.position, required this.horizontalOffset, required this.child, required this.controller, }); final Duration duration; final int position; final double? horizontalOffset; final Widget child; final PageController controller; @override State<AnimateWidget> createState() => _AnimateWidgetState(); } class _AnimateWidgetState extends State<AnimateWidget> with AutomaticKeepAliveClientMixin, SingleTickerProviderStateMixin{ @override bool get wantKeepAlive => true; late AnimationController animationController; int currentPage = 0; Timer? _timer; @override void initState() { super.initState(); animationController = AnimationController(vsync: this, duration: widget.duration); _timer = Timer(getDelay(), animationController.forward); widget.controller.addListener(() { currentPage = widget.controller.page!.round(); if(currentPage == widget.controller.page){ _timer = Timer(getDelay(), animationController.forward); } }); } @override void dispose() { _timer?.cancel(); animationController.dispose(); super.dispose(); } Duration getDelay(){ var delayInMilliSec = widget.duration.inMilliseconds ~/ 6; int getStaggeredListDuration(){ return widget.position * delayInMilliSec; } return Duration(milliseconds: getStaggeredListDuration()); } @override Widget build(BuildContext context) { super.build(context); return AnimatedBuilder( animation: animationController, builder: (context, child){ return _slideAnimation(animationController); } ); } Widget _slideAnimation(Animation<double> animationController){ Animation<double> offsetAnimation(double offset, Animation<double> animationController) { return Tween<double>(begin: offset, end: 0.0).animate( CurvedAnimation( parent: animationController, curve: const Interval(0.0, 1.0, curve: Curves.ease), ), ); } return Transform.translate( offset: Offset( widget.horizontalOffset == 0.0 ? 0.0 : offsetAnimation(widget.horizontalOffset!, animationController).value, 0.0, ), child: widget.child, ); } } इसके बाद, कॉलम विजेट में इस क्लास का उपयोग करने के लिए, हम नामक एक स्थिर विधि के साथ एक क्लास बनाएंगे जो एक सूची लौटाता है, इस विधि में, हम सभी आवश्यक पैरामीटर पास करते हैं, जिसमें एक सूची भी शामिल है। पैरामीटर वह जगह है जहाँ हम उन तत्वों की सूची पास करेंगे जिन्हें हम एनिमेट करेंगे। AnimateWidget toStaggeredList children children इसके बाद, हम बच्चों को मैप करेंगे, प्रत्येक बच्चे को के साथ लपेटेंगे। AnimateWidget class AnimateList{ static List<Widget>toStaggeredList({ required Duration duration, double? horizontalOffset, required PageController controller, required List<Widget>children, })=> children .asMap() .map((index, widget){ return MapEntry( index, AnimateWidget( duration: duration, position: index, horizontalOffset: horizontalOffset, controller: controller, child: widget, ) ); }) .values .toList(); } में, हम सूची में प्रत्येक चाइल्ड को सफलतापूर्वक एनिमेट करने के लिए आवश्यक पैरामीटर पास करते हैं। विधि का उपयोग करके, हम अब इसे उन दो पृष्ठों पर लागू कर सकते हैं जिन पर हम काम कर रहे हैं। AnimateWidget AnimateList.toStaggeredList class Page1 extends StatelessWidget { const Page1({super.key, required this.pageController}); final PageController pageController; @override Widget build(BuildContext context) { return SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( children: AnimateList.toStaggeredList( duration: const Duration(milliseconds: 375), controller: pageController, horizontalOffset: MediaQuery.of(context).size.width / 2, children: [ const EmptyCard(width: 250, height: 50,), const Padding( padding: EdgeInsets.only(top: 20), child: EmptyCard(width: 180, height: 80,), ), const Padding( padding: EdgeInsets.only(top: 20), child: EmptyCard(width: 270, height: 50,), ), const Padding( padding: EdgeInsets.symmetric(vertical: 20), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ EmptyCard(height: 50, width: 70), EmptyCard(height: 50, width: 70), EmptyCard(height: 50, width: 70), ], ), ), const EmptyCard(width: 250, height: 50,), const Padding( padding: EdgeInsets.only(top: 20), child: EmptyCard(width: 180, height: 80,), ), const Padding( padding: EdgeInsets.only(top: 20), child: EmptyCard(width: 270, height: 50,), ), const Padding( padding: EdgeInsets.symmetric(vertical: 20), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ EmptyCard(height: 50, width: 70), EmptyCard(height: 50, width: 70), EmptyCard(height: 50, width: 70), ], ), ), ], ), ), ); } } class Page2 extends StatelessWidget { const Page2({super.key, required this.pageController}); final PageController pageController; @override Widget build(BuildContext context) { return SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( children: AnimateList.toStaggeredList( duration: const Duration(milliseconds: 375), controller: pageController, horizontalOffset: MediaQuery.of(context).size.width / 2, children: [ const EmptyCard(width: 220, height: 70,), const Padding( padding: EdgeInsets.only(top: 20), child: EmptyCard(width: 300, height: 70,), ), const Padding( padding: EdgeInsets.only(top: 20), child: EmptyCard(width: 200, height: 50,), ), const Padding( padding: EdgeInsets.symmetric(vertical: 20), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ EmptyCard(height: 70, width: 70), EmptyCard(height: 70, width: 70), ], ), ), const EmptyCard(width: 220, height: 70,), const Padding( padding: EdgeInsets.only(top: 20), child: EmptyCard(width: 300, height: 70,), ), const Padding( padding: EdgeInsets.symmetric(vertical: 20), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ EmptyCard(height: 70, width: 70), EmptyCard(height: 70, width: 70), ], ), ), ], ), ), ); } } कॉलम विजेट के बच्चों में, हम पास करेंगे और आवश्यक पैरामीटर पास करेंगे, जिसमें कॉलम में प्रदर्शित किए जाने वाले विजेट शामिल हैं। इसके साथ, हमने स्वाइप पर ट्रिगर होने वाला एक स्टैगर्ड एनीमेशन सफलतापूर्वक बनाया है। आप पूरा कोड देख सकते हैं। AnimateList.toStaggeredList यहाँ यह हमारा अंतिम परिणाम है: निष्कर्ष हम इस ट्यूटोरियल के अंत में आ गए हैं। इस बिंदु पर, हमने माइक्रो-इंटरैक्शन की अवधारणा और उपयोगकर्ता अनुभव पर इसके प्रभाव को कवर किया। हमने पेज स्वाइप पर ट्रिगर किए गए कॉलम विजेट में आइटम के कंपित एनीमेशन बनाने की प्रक्रिया को भी देखा। आप अपने प्रोजेक्ट के उपयोगकर्ता अनुभव को बेहतर बनाने के लिए अपने ऐप में कई प्रकार के माइक्रो-इंटरैक्शन जोड़ सकते हैं; आप फ़्लटर में अधिक इंटरैक्टिव एनिमेशन बनाकर प्रयोग कर सकते हैं। अगर आपको यह लेख उपयोगी लगा, तो आप इसे लाइक या कमेंट करके अपना समर्थन दे सकते हैं। आप और भी संबंधित लेखों के लिए मुझे फॉलो भी कर सकते हैं। संदर्भ स्पंदन स्टैगर्ड एनीमेशन पैकेज