1. परिचय
ऐनिमेशन, आपके ऐप्लिकेशन के उपयोगकर्ता अनुभव को बेहतर बनाने, उपयोगकर्ता को ज़रूरी जानकारी देने, और आपके ऐप्लिकेशन को ज़्यादा बेहतर और इस्तेमाल करने में मज़ेदार बनाने का एक शानदार तरीका है.
Flutter के ऐनिमेशन फ़्रेमवर्क के बारे में खास जानकारी
Flutter, हर फ़्रेम पर विजेट ट्री के किसी हिस्से को फिर से बनाकर, ऐनिमेशन इफ़ेक्ट दिखाता है. यह पहले से बने ऐनिमेशन इफ़ेक्ट और अन्य एपीआई उपलब्ध कराता है, ताकि ऐनिमेशन बनाना और कंपोज करना आसान हो.
- इंप्लिसिट ऐनिमेशन, पहले से बने ऐनिमेशन इफ़ेक्ट होते हैं. ये पूरे ऐनिमेशन को अपने-आप चलाते हैं. जब ऐनिमेशन की टारगेट वैल्यू बदलती है, तो यह ऐनिमेशन को मौजूदा वैल्यू से टारगेट वैल्यू तक चलाता है. साथ ही, बीच में हर वैल्यू दिखाता है, ताकि विजेट आसानी से ऐनिमेट हो सके. इंप्लिसिट ऐनिमेशन के उदाहरणों में
AnimatedSize
,AnimatedScale
, औरAnimatedPositioned
शामिल हैं. - अश्लील ऐनिमेशन भी पहले से बने ऐनिमेशन इफ़ेक्ट होते हैं. हालांकि, इनका इस्तेमाल करने के लिए,
Animation
ऑब्जेक्ट की ज़रूरत होती है. उदाहरण के लिए,SizeTransition
,ScaleTransition
याPositionedTransition
. - ऐनिमेशन एक क्लास है, जो चल रहे या बंद किए गए ऐनिमेशन को दिखाती है. यह वैल्यू से बनी होती है, जो उस टारगेट वैल्यू को दिखाती है जिस पर ऐनिमेशन चल रहा है. साथ ही, इसमें स्टेटस भी होता है, जो किसी भी समय स्क्रीन पर ऐनिमेशन की मौजूदा वैल्यू दिखाता है. यह
Listenable
का सबक्लास है. ऐनिमेशन चलने के दौरान स्टेटस में बदलाव होने पर, यह अपने लिसनर को सूचना देता है. - AnimationController, ऐनिमेशन बनाने और उसकी स्थिति को कंट्रोल करने का एक तरीका है.
forward()
,reset()
,stop()
, औरrepeat()
जैसे तरीकों का इस्तेमाल करके, ऐनिमेशन को कंट्रोल किया जा सकता है. इसके लिए, आपको ऐनिमेशन के असर को तय करने की ज़रूरत नहीं होती. जैसे, स्केल, साइज़ या पोज़िशन. - Tweens का इस्तेमाल, शुरुआत और आखिर की वैल्यू के बीच वैल्यू को इंटरपोलेट करने के लिए किया जाता है. साथ ही, इनका इस्तेमाल किसी भी तरह की वैल्यू के लिए किया जा सकता है, जैसे कि डबल,
Offset
याColor
. - कर्व का इस्तेमाल, समय के साथ किसी पैरामीटर में होने वाले बदलाव की दर में बदलाव करने के लिए किया जाता है. जब कोई ऐनिमेशन चलता है, तो आम तौर पर ईज़िंग कर्व लागू किया जाता है, ताकि ऐनिमेशन की शुरुआत या आखिर में बदलाव की दर को तेज़ या धीमा किया जा सके. कर्व, 0.0 से 1.0 के बीच की इनपुट वैल्यू लेते हैं और 0.0 से 1.0 के बीच की आउटपुट वैल्यू दिखाते हैं.
आपको क्या बनाना है
इस कोडलैब में, आपको एक ऐसा क्विज़ गेम बनाना है जिसमें कई विकल्प हों. इसमें अलग-अलग ऐनिमेशन इफ़ेक्ट और तकनीकें होंगी.
आपको ये करने का तरीका दिखेगा...
- ऐसा विजेट बनाएं जिसका साइज़ और रंग ऐनिमेशन के साथ बदलता हो
- 3D कार्ड फ़्लिप इफ़ेक्ट बनाना
- ऐनिमेशन पैकेज में पहले से मौजूद बेहतरीन ऐनिमेशन इफ़ेक्ट का इस्तेमाल करना
- Android के नए वर्शन पर उपलब्ध, पीछे जाने पर झलक दिखाने वाले हाथ के जेस्चर की सुविधा जोड़ें
आपको इनके बारे में जानकारी मिलेगी
इस कोडलैब में आपको ये चीज़ें सीखने को मिलेंगी:
- ऐनिमेशन वाले इफ़ेक्ट का इस्तेमाल करने का तरीका. इससे, बहुत सारे कोड के बिना बेहतरीन ऐनिमेशन बनाए जा सकते हैं.
AnimatedSwitcher
याAnimationController
जैसे पहले से बने ऐनिमेट किए गए विजेट का इस्तेमाल करके, अपने इफ़ेक्ट कॉन्फ़िगर करने के लिए, ऐनिमेशन वाले इफ़ेक्ट का इस्तेमाल करने का तरीका.- 3D इफ़ेक्ट दिखाने वाला अपना विजेट बनाने के लिए,
AnimationController
का इस्तेमाल करने का तरीका. - कम से कम सेटअप के साथ शानदार ऐनिमेशन इफ़ेक्ट दिखाने के लिए,
animations
पैकेज का इस्तेमाल करने का तरीका.
आपको इन चीज़ों की ज़रूरत होगी
- Flutter SDK टूल
- कोई IDE, जैसे कि VSCode या Android Studio / IntelliJ
2. Flutter डेवलपमेंट एनवायरमेंट सेट अप करना
इस लैब को पूरा करने के लिए, आपके पास दो सॉफ़्टवेयर होने चाहिए — Flutter SDK टूल और एडिटर.
इनमें से किसी भी डिवाइस का इस्तेमाल करके, कोडलैब चलाया जा सकता है:
- आपके कंप्यूटर से कनेक्ट किया गया Android (सातवें चरण में, अनुमानित बैक को लागू करने के लिए सुझाया गया) या iOS डिवाइस, जो डेवलपर मोड पर सेट हो.
- iOS सिम्युलेटर (इसके लिए, Xcode टूल इंस्टॉल करने की ज़रूरत है).
- Android एमुलेटर (Android Studio में सेटअप करना ज़रूरी है).
- ब्राउज़र (डीबग करने के लिए Chrome ज़रूरी है).
- Windows, Linux या macOS डेस्कटॉप कंप्यूटर. आपको उस प्लैटफ़ॉर्म पर ऐप्लिकेशन बनाना होगा जिस पर आपको उसे डिप्लॉय करना है. इसलिए, अगर आपको Windows डेस्कटॉप ऐप्लिकेशन बनाना है, तो आपको सही बिल्ड चेन ऐक्सेस करने के लिए, Windows पर डेवलप करना होगा. ऑपरेटिंग सिस्टम के हिसाब से कुछ ज़रूरी शर्तें होती हैं. इनके बारे में ज़्यादा जानकारी docs.flutter.dev/desktop पर दी गई है.
अपने इंस्टॉलेशन की पुष्टि करना
Flutter Doctor टूल का इस्तेमाल करके, यह पुष्टि करें कि आपका Flutter SDK टूल सही तरीके से कॉन्फ़िगर किया गया है और आपने ऊपर दिए गए टारगेट प्लैटफ़ॉर्म में से कम से कम एक को इंस्टॉल किया है:
$ flutter doctor Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel stable, 3.24.2, on macOS 14.6.1 23G93 darwin-arm64, locale en) [✓] Android toolchain - develop for Android devices [✓] Xcode - develop for iOS and macOS [✓] Chrome - develop for the web [✓] Android Studio [✓] IntelliJ IDEA Ultimate Edition [✓] VS Code [✓] Connected device (4 available) [✓] Network resources • No issues found!
3. स्टार्टर ऐप्लिकेशन चलाना
स्टार्टर ऐप्लिकेशन डाउनलोड करना
GitHub पर flutter/samples डेटा स्टोर करने की जगह से, स्टार्ट ऐप्लिकेशन को क्लोन करने के लिए git
का इस्तेमाल करें.
$ git clone https://github.com/flutter/codelabs.git $ cd codelabs/animations/step_01/
इसके अलावा, सोर्स कोड को .zip फ़ाइल के तौर पर डाउनलोड किया जा सकता है.
ऐप्लिकेशन चलाना
ऐप्लिकेशन चलाने के लिए, flutter run
कमांड का इस्तेमाल करें और टारगेट किए गए डिवाइस की जानकारी दें, जैसे कि android
, ios
या chrome
. जिन प्लैटफ़ॉर्म पर यह सुविधा काम करती है उनकी पूरी सूची देखने के लिए, इस्तेमाल किए जा सकने वाले प्लैटफ़ॉर्म पेज पर जाएं.
$ flutter run -d android
अपनी पसंद के आईडीई का इस्तेमाल करके, ऐप्लिकेशन को चलाया और डीबग भी किया जा सकता है. ज़्यादा जानकारी के लिए, Flutter का आधिकारिक दस्तावेज़ देखें.
कोड के बारे में जानकारी
स्टार्टर ऐप्लिकेशन, एक मल्टी-चॉइस क्विज़ गेम है. इसमें मॉडल-व्यू-व्यू-मॉडल या MVVM डिज़ाइन पैटर्न के हिसाब से दो स्क्रीन हैं. QuestionScreen
(व्यू), QuizViewModel
(व्यू-मॉडल) क्लास का इस्तेमाल करके, उपयोगकर्ता से QuestionBank
(मॉडल) क्लास के कई विकल्प वाले सवाल पूछता है.
- home_screen.dart - नया गेम बटन वाली स्क्रीन दिखाता है
- main.dart - Material 3 का इस्तेमाल करने और होम स्क्रीन दिखाने के लिए,
MaterialApp
को कॉन्फ़िगर करता है - model.dart - पूरे ऐप्लिकेशन में इस्तेमाल की जाने वाली मुख्य क्लास के बारे में बताता है
- question_screen.dart - क्विज़ गेम का यूज़र इंटरफ़ेस दिखाता है
- view_model.dart - क्विज़ गेम की स्थिति और लॉजिक को सेव करता है. इसे
QuestionScreen
दिखाता है
फ़िलहाल, ऐप्लिकेशन में ऐनिमेशन वाले किसी भी इफ़ेक्ट का इस्तेमाल नहीं किया जा सकता. हालांकि, जब उपयोगकर्ता नया गेम बटन दबाता है, तब Flutter की Navigator
क्लास से डिफ़ॉल्ट व्यू ट्रांज़िशन दिखता है.
4. ऐनिमेशन के इम्प्लीसिट इफ़ेक्ट का इस्तेमाल करना
कई मामलों में, इम्प्लीसिट ऐनिमेशन का इस्तेमाल करना बेहतर होता है, क्योंकि इसके लिए किसी खास कॉन्फ़िगरेशन की ज़रूरत नहीं होती. इस सेक्शन में, आपको StatusBar
विजेट को अपडेट करना होगा, ताकि यह ऐनिमेटेड स्कोरबोर्ड दिखा सके. सामान्य इम्प्लीसिट ऐनिमेशन इफ़ेक्ट ढूंढने के लिए, ImplicitlyAnimatedWidget एपीआई का दस्तावेज़ ब्राउज़ करें.
ऐनिमेशन वाला स्कोरबोर्ड विजेट बनाना
इस कोड की मदद से, lib/scoreboard.dart
नाम की नई फ़ाइल बनाएं:
lib/scoreboard.dart
import 'package:flutter/material.dart';
class Scoreboard extends StatelessWidget {
final int score;
final int totalQuestions;
const Scoreboard({
super.key,
required this.score,
required this.totalQuestions,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
for (var i = 0; i < totalQuestions; i++)
Icon(
Icons.star,
size: 50,
color:
score < i + 1 ? Colors.grey.shade400 : Colors.yellow.shade700,
)
],
),
);
}
}
इसके बाद, StatusBar
विजेट के चाइल्ड में Scoreboard
विजेट जोड़ें. साथ ही, उन Text
विजेट की जगह पर Scoreboard
विजेट जोड़ें जो पहले स्कोर और सवालों की कुल संख्या दिखाते थे. आपका एडिटर, फ़ाइल में सबसे ऊपर ज़रूरी import "scoreboard.dart"
अपने-आप जोड़ देगा.
lib/question_screen.dart
class StatusBar extends StatelessWidget {
final QuizViewModel viewModel;
const StatusBar({required this.viewModel, super.key});
@override
Widget build(BuildContext context) {
return Card(
elevation: 4,
child: Padding(
padding: EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Scoreboard( // NEW
score: viewModel.score, // NEW
totalQuestions: viewModel.totalQuestions, // NEW
),
],
),
),
);
}
}
यह विजेट, हर सवाल के लिए स्टार आइकॉन दिखाता है. जब किसी सवाल का सही जवाब दिया जाता है, तो बिना किसी ऐनिमेशन के एक और तारा तुरंत रोशन हो जाता है. यहां दिए गए चरणों में, आपको उपयोगकर्ता को यह बताने में मदद मिलेगी कि उसके स्कोर में बदलाव हुआ है. इसके लिए, स्कोर के साइज़ और रंग में ऐनिमेशन का इस्तेमाल किया जाएगा.
ऐनिमेशन के किसी इफ़ेक्ट का इस्तेमाल करना
AnimatedStar
नाम का एक नया विजेट बनाएं. यह विजेट, AnimatedScale
विजेट का इस्तेमाल करके, स्टार के चालू होने पर scale
की वैल्यू को 0.5
से 1.0
में बदलता है:
lib/scoreboard.dart
import 'package:flutter/material.dart';
class Scoreboard extends StatelessWidget {
final int score;
final int totalQuestions;
const Scoreboard({
super.key,
required this.score,
required this.totalQuestions,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
for (var i = 0; i < totalQuestions; i++)
AnimatedStar( // NEW
isActive: score > i, // NEW
) // NEW
],
),
);
}
}
class AnimatedStar extends StatelessWidget { // Add from here...
final bool isActive;
final Duration _duration = const Duration(milliseconds: 1000);
final Color _deactivatedColor = Colors.grey.shade400;
final Color _activatedColor = Colors.yellow.shade700;
AnimatedStar({super.key, required this.isActive});
@override
Widget build(BuildContext context) {
return AnimatedScale(
scale: isActive ? 1.0 : 0.5,
duration: _duration,
child: Icon(
Icons.star,
size: 50,
color: isActive ? _activatedColor : _deactivatedColor,
),
);
}
} // To here.
अब, जब कोई उपयोगकर्ता किसी सवाल का सही जवाब देता है, तो AnimatedStar
विजेट, अपने-आप होने वाले ऐनिमेशन का इस्तेमाल करके अपना साइज़ अपडेट करता है. यहां Icon
के color
में ऐनिमेशन नहीं है, सिर्फ़ scale
में है. यह ऐनिमेशन, AnimatedScale
विजेट से किया जाता है.
दो वैल्यू के बीच इंटरपोलेट करने के लिए, ट्वीन का इस्तेमाल करना
ध्यान दें कि isActive
फ़ील्ड के 'सही' में बदलने के तुरंत बाद, AnimatedStar
विजेट का रंग बदल जाता है.
ऐनिमेशन वाले रंग का असर पाने के लिए, AnimatedContainer
विजेट का इस्तेमाल किया जा सकता है. यह विजेट, ImplicitlyAnimatedWidget
का एक अन्य सबक्लास है. यह अपने सभी एट्रिब्यूट को अपने-आप ऐनिमेट कर सकता है. इनमें रंग भी शामिल है. माफ़ करें, हमारे विजेट में कंटेनर के बजाय आइकॉन दिखाना ज़रूरी है.
AnimatedIcon
को भी आज़माया जा सकता है. इससे आइकॉन के आकार के बीच ट्रांज़िशन इफ़ेक्ट लागू होते हैं. हालांकि, AnimatedIcons
क्लास में स्टार आइकॉन डिफ़ॉल्ट रूप से लागू नहीं होता.
इसके बजाय, हम ImplicitlyAnimatedWidget
के किसी दूसरे सबक्लास का इस्तेमाल करेंगे, जिसे TweenAnimationBuilder
कहा जाता है. यह पैरामीटर के तौर पर Tween
लेता है. ट्वीन एक क्लास है, जो दो वैल्यू (begin
और end
) लेती है और उनके बीच की वैल्यू का हिसाब लगाती है, ताकि ऐनिमेशन उन्हें दिखा सके. इस उदाहरण में, हम ColorTween
का इस्तेमाल करेंगे. यह Tween<Color>
इंटरफ़ेस के मुताबिक है, जो ऐनिमेशन इफ़ेक्ट बनाने के लिए ज़रूरी है.
Icon
विजेट चुनें और अपने आईडीई में "बिल्डर के साथ रैप करें" क्विक ऐक्शन का इस्तेमाल करें. इसके बाद, नाम को TweenAnimationBuilder
में बदलें. इसके बाद, कुल समय और ColorTween
डालें.
lib/scoreboard.dart
class AnimatedStar extends StatelessWidget {
final bool isActive;
final Duration _duration = const Duration(milliseconds: 1000);
final Color _deactivatedColor = Colors.grey.shade400;
final Color _activatedColor = Colors.yellow.shade700;
AnimatedStar({super.key, required this.isActive});
@override
Widget build(BuildContext context) {
return AnimatedScale(
scale: isActive ? 1.0 : 0.5,
duration: _duration,
child: TweenAnimationBuilder( // Add from here...
duration: _duration,
tween: ColorTween(
begin: _deactivatedColor,
end: isActive ? _activatedColor : _deactivatedColor,
),
builder: (context, value, child) { // To here.
return Icon(
Icons.star,
size: 50,
color: value, // Modify from here...
);
}, // To here.
),
);
}
}
अब नया ऐनिमेशन देखने के लिए, ऐप्लिकेशन को हॉट-रीलोड करें.
ध्यान दें कि ColorTween
पैरामीटर की वैल्यू के आधार पर, ColorTween
की end
वैल्यू बदल जाती है.isActive
ऐसा इसलिए होता है, क्योंकि जब भी Tween.end
की वैल्यू बदलती है, तो TweenAnimationBuilder
अपना ऐनिमेशन फिर से चलाता है. ऐसा होने पर, नया ऐनिमेशन मौजूदा ऐनिमेशन वैल्यू से लेकर नई आखिरी वैल्यू तक चलता है. इससे, किसी भी समय (ऐनिमेशन चलने के दौरान भी) रंग बदला जा सकता है. साथ ही, बीच की सही वैल्यू के साथ ऐनिमेशन का बेहतर असर दिखाया जा सकता है.
कर्व लागू करना
ये दोनों ऐनिमेशन इफ़ेक्ट एक ही रफ़्तार से चलते हैं. हालांकि, तेज़ी या धीमी रफ़्तार से चलने पर, ऐनिमेशन अक्सर ज़्यादा दिलचस्प और जानकारी देने वाले लगते हैं.
Curve
, ईज़िंग फ़ंक्शन लागू करता है. इससे, समय के साथ किसी पैरामीटर में होने वाले बदलाव की दर तय होती है. Flutter, Curves
क्लास में पहले से बने ईज़िंग कर्व का कलेक्शन उपलब्ध कराता है. जैसे, easeIn
या easeOut
.
इन डायग्राम (Curves
एपीआई दस्तावेज़ वाले पेज पर उपलब्ध) से पता चलता है कि कर्व कैसे काम करते हैं. कर्व, 0.0 से 1.0 के बीच की इनपुट वैल्यू (x ऐक्सिस पर दिखती है) को 0.0 से 1.0 के बीच की आउटपुट वैल्यू (y ऐक्सिस पर दिखती है) में बदल देते हैं. इन डायग्राम में यह भी दिखाया गया है कि आसानी से बदलने वाले कर्व का इस्तेमाल करने पर, अलग-अलग ऐनिमेशन इफ़ेक्ट कैसा दिखते हैं.
AnimatedStar में _curve
नाम का नया फ़ील्ड बनाएं और उसे AnimatedScale
और TweenAnimationBuilder
विजेट के पैरामीटर के तौर पर पास करें.
lib/scoreboard.dart
class AnimatedStar extends StatelessWidget {
final bool isActive;
final Duration _duration = const Duration(milliseconds: 1000);
final Color _deactivatedColor = Colors.grey.shade400;
final Color _activatedColor = Colors.yellow.shade700;
final Curve _curve = Curves.elasticOut; // NEW
AnimatedStar({super.key, required this.isActive});
@override
Widget build(BuildContext context) {
return AnimatedScale(
scale: isActive ? 1.0 : 0.5,
curve: _curve, // NEW
duration: _duration,
child: TweenAnimationBuilder(
curve: _curve, // NEW
duration: _duration,
tween: ColorTween(
begin: _deactivatedColor,
end: isActive ? _activatedColor : _deactivatedColor,
),
builder: (context, value, child) {
return Icon(
Icons.star,
size: 50,
color: value,
);
},
),
);
}
}
इस उदाहरण में, elasticOut
कर्व से स्प्रिंग का बढ़ा-चढ़ाकर दिखाया गया इफ़ेक्ट मिलता है. यह इफ़ेक्ट स्प्रिंग की गति से शुरू होता है और आखिर में बैलेंस हो जाता है.
AnimatedSize
और TweenAnimationBuilder
पर लागू किया गया यह कर्व देखने के लिए, ऐप्लिकेशन को हॉट रीलोड करें.
धीमे ऐनिमेशन चालू करने के लिए DevTools का इस्तेमाल करना
किसी भी ऐनिमेशन इफ़ेक्ट को डीबग करने के लिए, Flutter DevTools में आपके ऐप्लिकेशन के सभी ऐनिमेशन को धीमा करने का तरीका दिया गया है. इससे, ऐनिमेशन को ज़्यादा साफ़ तौर पर देखा जा सकता है.
DevTools खोलने के लिए, पक्का करें कि ऐप्लिकेशन डीबग मोड में चल रहा हो. इसके बाद, विजेट इंस्पेक्टर खोलें. इसके लिए, VSCode में डीबग टूलबार में जाकर विजेट इंस्पेक्टर को चुनें या IntelliJ / Android Studio में डीबग टूल विंडो में जाकर, Flutter DevTools खोलें बटन को चुनें.
विजेट की जांच करने वाला टूल खुलने के बाद, टूलबार में मौजूद ऐनिमेशन धीमा करें बटन पर क्लिक करें.
5. अश्लील ऐनिमेशन इफ़ेक्ट का इस्तेमाल करना
इम्प्लीसिट ऐनिमेशन की तरह, एक्सप्लिशिट ऐनिमेशन भी पहले से बने ऐनिमेशन इफ़ेक्ट होते हैं. हालांकि, टारगेट वैल्यू के बजाय, ये पैरामीटर के तौर पर Animation
ऑब्जेक्ट लेते हैं. इस वजह से, ये ऐसे मामलों में काम के होते हैं जहां ऐनिमेशन पहले से ही नेविगेशन ट्रांज़िशन, AnimatedSwitcher
या AnimationController
से तय होता है.
अश्लील ऐनिमेशन इफ़ेक्ट का इस्तेमाल करना
साफ़ तौर पर दिखने वाले ऐनिमेशन इफ़ेक्ट का इस्तेमाल शुरू करने के लिए, Card
विजेट को AnimatedSwitcher
में रैप करें.
lib/question_screen.dart
class QuestionCard extends StatelessWidget {
final String? question;
const QuestionCard({
required this.question,
super.key,
});
@override
Widget build(BuildContext context) {
return AnimatedSwitcher( // NEW
duration: const Duration(milliseconds: 300), // NEW
child: Card(
key: ValueKey(question),
elevation: 4,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
question ?? '',
style: Theme.of(context).textTheme.displaySmall,
),
),
), // NEW
);
}
}
AnimatedSwitcher
डिफ़ॉल्ट रूप से क्रॉस-फ़ेड इफ़ेक्ट का इस्तेमाल करता है. हालांकि, transitionBuilder
पैरामीटर का इस्तेमाल करके, इसे बदला जा सकता है. ट्रांज़िशन बिल्डर, AnimatedSwitcher
और Animation
ऑब्जेक्ट को पास किया गया चाइल्ड विजेट उपलब्ध कराता है. साफ़ तौर पर दिखाने वाले ऐनिमेशन का इस्तेमाल करने का यह एक शानदार मौका है.
इस कोडलैब में, हम साफ़ तौर पर दिखने वाले पहले ऐनिमेशन के तौर पर SlideTransition
का इस्तेमाल करेंगे. इसमें एक Animation<Offset>
होता है, जो शुरू और खत्म होने के ऑफ़सेट की जानकारी देता है. इन ऑफ़सेट के बीच, इनकमिंग और आउटगोइंग विजेट मूव करेंगे.
ट्वीन में एक हेल्पर फ़ंक्शन, animate()
होता है. यह किसी भी Animation
को, ट्वीन के साथ लागू किए गए किसी दूसरे Animation
में बदल देता है. इसका मतलब है कि Tween<Offset>
का इस्तेमाल, AnimatedSwitcher
से मिले Animation<double>
को Animation<Offset>
में बदलने के लिए किया जा सकता है, ताकि उसे SlideTransition
विजेट को दिया जा सके.
lib/question_screen.dart
class QuestionCard extends StatelessWidget {
final String? question;
const QuestionCard({
required this.question,
super.key,
});
@override
Widget build(BuildContext context) {
return AnimatedSwitcher(
transitionBuilder: (child, animation) { // Add from here...
final curveAnimation =
CurveTween(curve: Curves.easeInCubic).animate(animation);
final offsetAnimation =
Tween<Offset>(begin: Offset(-0.1, 0.0), end: Offset.zero)
.animate(curveAnimation);
return SlideTransition(position: offsetAnimation, child: child);
}, // To here.
duration: const Duration(milliseconds: 300),
child: Card(
key: ValueKey(question),
elevation: 4,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
question ?? '',
style: Theme.of(context).textTheme.displaySmall,
),
),
),
);
}
}
ध्यान दें कि यह Animation
पर Curve
लागू करने के लिए Tween.animate
का इस्तेमाल करता है. इसके बाद, इसे 0.0 से 1.0 तक की रेंज वाले Tween<double>
से, x-ऐक्सिस पर -0.1 से 0.0 तक ट्रांज़िशन करने वाले Tween<Offset>
में बदलता है.
इसके अलावा, ऐनिमेशन क्लास में drive()
फ़ंक्शन होता है, जो किसी भी Tween
(या Animatable
) को लेकर उसे नए Animation
में बदल देता है. इससे ट्वीन को "चेन" किया जा सकता है, जिससे नतीजा देने वाला कोड ज़्यादा छोटा हो जाता है:
lib/question_screen.dart
transitionBuilder: (child, animation) {
var offsetAnimation = animation
.drive(CurveTween(curve: Curves.easeInCubic))
.drive(Tween<Offset>(begin: Offset(-0.1, 0.0), end: Offset.zero));
return SlideTransition(position: offsetAnimation, child: child);
},
साफ़ तौर पर सेक्शुअल ऐक्शन दिखाने वाले ऐनिमेशन का एक और फ़ायदा यह है कि उन्हें आसानी से एक साथ कंपोज किया जा सकता है. FadeTransition नाम का एक और साफ़ तौर पर दिखने वाला ऐनिमेशन जोड़ें. यह ऐनिमेशन, SlideTransition विजेट को रैप करके, उसी घुमावदार ऐनिमेशन का इस्तेमाल करता है.
lib/question_screen.dart
return AnimatedSwitcher(
transitionBuilder: (child, animation) {
final curveAnimation =
CurveTween(curve: Curves.easeInCubic).animate(animation);
final offsetAnimation =
Tween<Offset>(begin: Offset(-0.1, 0.0), end: Offset.zero)
.animate(curveAnimation);
final fadeInAnimation = curveAnimation; // NEW
return FadeTransition( // NEW
opacity: fadeInAnimation, // NEW
child: SlideTransition(position: offsetAnimation, child: child), // NEW
); // NEW
},
layoutBuilder को पसंद के मुताबिक बनाना
आपको AnimationSwitcher में एक छोटी समस्या दिख सकती है. जब कोई QuestionCard किसी नए सवाल पर स्विच करता है, तो ऐनिमेशन चलने के दौरान वह उसे उपलब्ध जगह के बीच में दिखाता है. हालांकि, ऐनिमेशन बंद होने पर, विजेट स्क्रीन पर सबसे ऊपर दिखता है. इससे ऐनिमेशन में रुकावट आती है, क्योंकि सवाल वाले कार्ड की फ़ाइनल पोज़िशन, ऐनिमेशन चलने के दौरान की पोज़िशन से मेल नहीं खाती.
इसे ठीक करने के लिए, AnimatedSwitcher में layoutBuilder पैरामीटर भी है. इसका इस्तेमाल लेआउट तय करने के लिए किया जा सकता है. लेआउट बिल्डर को कॉन्फ़िगर करके, कार्ड को स्क्रीन पर सबसे ऊपर अलाइन करने के लिए, इस फ़ंक्शन का इस्तेमाल करें:
lib/question_screen.dart
@override
Widget build(BuildContext context) {
return AnimatedSwitcher(
layoutBuilder: (currentChild, previousChildren) {
return Stack(
alignment: Alignment.topCenter,
children: <Widget>[
...previousChildren,
if (currentChild != null) currentChild,
],
);
},
यह कोड, AnimatedSwitcher क्लास के defaultLayoutBuilder का बदला हुआ वर्शन है. हालांकि, इसमें Alignment.center
के बजाय Alignment.topCenter
का इस्तेमाल किया गया है.
खास जानकारी
- साफ़ तौर पर दिखने वाले ऐनिमेशन, ऐनिमेशन इफ़ेक्ट होते हैं. ये इफ़ेक्ट, ऐनिमेशन ऑब्जेक्ट का इस्तेमाल करते हैं. वहीं, ImplicitlyAnimatedWidgets, टारगेट वैल्यू और अवधि का इस्तेमाल करते हैं
- ऐनिमेशन क्लास, चल रहे ऐनिमेशन को दिखाती है, लेकिन किसी खास इफ़ेक्ट के बारे में नहीं बताती.
- किसी ऐनिमेशन में CurveTween का इस्तेमाल करके, ट्रिन और कर्व लागू करने के लिए, Tween().animate या Animation.drive() का इस्तेमाल करें.
- AnimatedSwitcher के layoutBuilder पैरामीटर का इस्तेमाल करके, यह तय करें कि इसके चाइल्ड एलिमेंट किस तरह दिखें.
6. ऐनिमेशन की स्थिति कंट्रोल करना
अब तक, फ़्रेमवर्क ने हर ऐनिमेशन को अपने-आप चलाया है. इम्प्लीस ऐनिमेशन अपने-आप चलते हैं. वहीं, साफ़ तौर पर दिखने वाले ऐनिमेशन इफ़ेक्ट के लिए, ऐनिमेशन की ज़रूरत होती है. इस सेक्शन में, आपको AnimationController का इस्तेमाल करके अपने ऐनिमेशन ऑब्जेक्ट बनाने का तरीका पता चलेगा. साथ ही, Tweens को एक साथ जोड़ने के लिए, TweenSequence का इस्तेमाल करने का तरीका भी पता चलेगा.
AnimationController का इस्तेमाल करके ऐनिमेशन चलाना
AnimationController का इस्तेमाल करके ऐनिमेशन बनाने के लिए, आपको यह तरीका अपनाना होगा:
- StatefulWidget बनाना
- अपने AnimationController को टिकर देने के लिए, अपनी State क्लास में SingleTickerProviderStateMixin मिक्सिन का इस्तेमाल करें
- initState लाइफ़साइकल मेथड में AnimationController को शुरू करें. इसके लिए,
vsync
(TickerProvider) पैरामीटर को मौजूदा State ऑब्जेक्ट दें. - पक्का करें कि जब भी AnimationController अपने लिसनर को सूचना दे, तब आपका विजेट फिर से बन जाए. इसके लिए, AnimatedBuilder का इस्तेमाल करें या listen() और setState को मैन्युअल तरीके से कॉल करें.
flip_effect.dart नाम की एक नई फ़ाइल बनाएं और नीचे दिया गया कोड कॉपी करके चिपकाएं:
lib/flip_effect.dart
import 'dart:math' as math;
import 'package:flutter/widgets.dart';
class CardFlipEffect extends StatefulWidget {
final Widget child;
final Duration duration;
const CardFlipEffect({
super.key,
required this.child,
required this.duration,
});
@override
State<CardFlipEffect> createState() => _CardFlipEffectState();
}
class _CardFlipEffectState extends State<CardFlipEffect>
with SingleTickerProviderStateMixin {
late final AnimationController _animationController;
Widget? _previousChild;
@override
void initState() {
super.initState();
_animationController =
AnimationController(vsync: this, duration: widget.duration);
_animationController.addListener(() {
if (_animationController.value == 1) {
_animationController.reset();
}
});
}
@override
void didUpdateWidget(covariant CardFlipEffect oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.child.key != oldWidget.child.key) {
_handleChildChanged(widget.child, oldWidget.child);
}
}
void _handleChildChanged(Widget newChild, Widget previousChild) {
_previousChild = previousChild;
_animationController.forward();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return Transform(
alignment: Alignment.center,
transform: Matrix4.identity()
..rotateX(_animationController.value * math.pi),
child: _animationController.isAnimating
? _animationController.value < 0.5
? _previousChild
: Transform.flip(flipY: true, child: child)
: child,
);
},
child: widget.child,
);
}
}
यह क्लास, AnimationController को सेट अप करती है. साथ ही, जब भी फ़्रेमवर्क didUpdateWidget को कॉल करता है, तब ऐनिमेशन को फिर से चलाती है. इससे यह पता चलता है कि विजेट का कॉन्फ़िगरेशन बदल गया है और हो सकता है कि कोई नया चाइल्ड विजेट हो.
AnimatedBuilder यह पक्का करता है कि जब भी AnimationController अपने लिसनर को सूचना दे, तब विजेट ट्री को फिर से बनाया जाए. साथ ही, कार्ड को फ़्लिप करने के लिए, 3D रोटेशन इफ़ेक्ट लागू करने के लिए Transform विजेट का इस्तेमाल किया जाता है.
इस विजेट का इस्तेमाल करने के लिए, हर जवाब कार्ड को CardFlipEffect विजेट में रैप करें. कार्ड विजेट के लिए key
देना न भूलें:
lib/question_screen.dart
@override
Widget build(BuildContext context) {
return GridView.count(
shrinkWrap: true,
crossAxisCount: 2,
childAspectRatio: 5 / 2,
children: List.generate(answers.length, (index) {
var color = Theme.of(context).colorScheme.primaryContainer;
if (correctAnswer == index) {
color = Theme.of(context).colorScheme.tertiaryContainer;
}
return CardFlipEffect( // NEW
duration: const Duration(milliseconds: 300), // NEW
child: Card.filled( // NEW
key: ValueKey(answers[index]), // NEW
color: color,
elevation: 2,
margin: EdgeInsets.all(8),
clipBehavior: Clip.hardEdge,
child: InkWell(
onTap: () => onTapped(index),
child: Padding(
padding: EdgeInsets.all(16.0),
child: Center(
child: Text(
answers.length > index ? answers[index] : '',
style: Theme.of(context).textTheme.titleMedium,
overflow: TextOverflow.clip,
),
),
),
),
), // NEW
);
}),
);
}
अब CardFlipEffect विजेट का इस्तेमाल करके, जवाब वाले कार्ड को पलटते हुए देखने के लिए, ऐप्लिकेशन को हॉट-रीलोड करें.
आपको यह दिख सकता है कि यह क्लास, अश्लील ऐनिमेशन इफ़ेक्ट की तरह दिखती है. असल में, अपने वर्शन को लागू करने के लिए, AnimatedWidget क्लास को सीधे तौर पर एक्सटेंंड करना अक्सर एक अच्छा आइडिया होता है. माफ़ करें, इस क्लास को अपने स्टेट में पिछले विजेट को सेव करना होता है. इसलिए, इसे StatefulWidget का इस्तेमाल करना होगा. अपने हिसाब से ऐनिमेशन इफ़ेक्ट बनाने के बारे में ज़्यादा जानने के लिए, AnimatedWidget के लिए एपीआई दस्तावेज़ देखें.
TweenSequence का इस्तेमाल करके देरी जोड़ना
इस सेक्शन में, आपको CardFlipEffect विजेट में देरी जोड़नी होगी, ताकि हर कार्ड एक-एक करके फ़्लिप हो सके. शुरू करने के लिए, delayAmount
नाम का नया फ़ील्ड जोड़ें.
lib/flip_effect.dart
class CardFlipEffect extends StatefulWidget {
final Widget child;
final Duration duration;
final double delayAmount; // NEW
const CardFlipEffect({
super.key,
required this.child,
required this.duration,
required this.delayAmount, // NEW
});
@override
State<CardFlipEffect> createState() => _CardFlipEffectState();
}
इसके बाद, AnswerCards
बिल्ड करने के तरीके में delayAmount
जोड़ें.
lib/question_screen.dart
@override
Widget build(BuildContext context) {
return GridView.count(
shrinkWrap: true,
crossAxisCount: 2,
childAspectRatio: 5 / 2,
children: List.generate(answers.length, (index) {
var color = Theme.of(context).colorScheme.primaryContainer;
if (correctAnswer == index) {
color = Theme.of(context).colorScheme.tertiaryContainer;
}
return CardFlipEffect(
delayAmount: index.toDouble() / 2, // NEW
duration: const Duration(milliseconds: 300),
child: Card.filled(
key: ValueKey(answers[index]),
इसके बाद, _CardFlipEffectState
में एक नया ऐनिमेशन बनाएं, जो TweenSequence
का इस्तेमाल करके देरी लागू करता है. ध्यान दें कि यह Future.delayed
जैसी dart:async
लाइब्रेरी की किसी भी सुविधा का इस्तेमाल नहीं करता. ऐसा इसलिए होता है, क्योंकि देरी ऐनिमेशन का हिस्सा होती है. यह ऐसा नहीं है जिसे विजेट, AnimationController का इस्तेमाल करते समय साफ़ तौर पर कंट्रोल करता हो. इससे, DevTools में स्लो ऐनिमेशन चालू करते समय ऐनिमेशन इफ़ेक्ट को डीबग करना आसान हो जाता है. ऐसा इसलिए, क्योंकि यह एक ही TickerProvider का इस्तेमाल करता है.
TweenSequence
का इस्तेमाल करने के लिए, दो TweenSequenceItem
बनाएं. इनमें से एक में ConstantTween
शामिल करें, जो ऐनिमेशन को किसी तय समय के लिए 0 पर रखता है. साथ ही, एक सामान्य Tween
बनाएं, जो 0.0
से 1.0
तक जाता है.
lib/flip_effect.dart
class _CardFlipEffectState extends State<CardFlipEffect>
with SingleTickerProviderStateMixin {
late final AnimationController _animationController;
Widget? _previousChild;
late final Animation<double> _animationWithDelay; // NEW
@override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this, duration: widget.duration * (widget.delayAmount + 1));
_animationController.addListener(() {
if (_animationController.value == 1) {
_animationController.reset();
}
});
_animationWithDelay = TweenSequence<double>([ // NEW
if (widget.delayAmount > 0) // NEW
TweenSequenceItem( // NEW
tween: ConstantTween<double>(0.0), // NEW
weight: widget.delayAmount, // NEW
), // NEW
TweenSequenceItem( // NEW
tween: Tween(begin: 0.0, end: 1.0), // NEW
weight: 1.0, // NEW
), // NEW
]).animate(_animationController); // NEW
}
आखिर में, बिल्ड करने के तरीके में AnimationController के ऐनिमेशन को, देर से चलने वाले नए ऐनिमेशन से बदलें.
lib/flip_effect.dart
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _animationWithDelay, // Modify this line
builder: (context, child) {
return Transform(
alignment: Alignment.center,
transform: Matrix4.identity()
..rotateX(_animationWithDelay.value * math.pi), // And this line
child: _animationController.isAnimating
? _animationWithDelay.value < 0.5 // And this one.
? _previousChild
: Transform.flip(flipY: true, child: child)
: child,
);
},
child: widget.child,
);
}
अब ऐप्लिकेशन को हॉट रीलोड करें और देखें कि कार्ड एक-एक करके कैसे फ़्लिप होते हैं. Transform
विजेट से मिलने वाले 3D इफ़ेक्ट के पर्सपेक्टिव को बदलने की कोशिश करें.
7. कस्टम नेविगेशन ट्रांज़िशन का इस्तेमाल करना
अब तक, हमने एक स्क्रीन पर इफ़ेक्ट को पसंद के मुताबिक बनाने का तरीका देखा है. हालांकि, ऐनिमेशन का इस्तेमाल करने का एक और तरीका है. इसका इस्तेमाल, स्क्रीन के बीच ट्रांज़िशन करने के लिए किया जा सकता है. इस सेक्शन में, आपको स्क्रीन ट्रांज़िशन में ऐनिमेशन इफ़ेक्ट लागू करने का तरीका पता चलेगा. इसके लिए, पहले से मौजूद ऐनिमेशन इफ़ेक्ट और pub.dev पर मौजूद आधिकारिक ऐनिमेशन पैकेज से मिलने वाले पहले से बने ऐनिमेशन इफ़ेक्ट का इस्तेमाल किया जाएगा
नेविगेशन ट्रांज़िशन को ऐनिमेट करना
PageRouteBuilder
क्लास एक Route
है. इसकी मदद से, ट्रांज़िशन ऐनिमेशन को पसंद के मुताबिक बनाया जा सकता है. इससे आपको इसके transitionBuilder
कॉलबैक को बदलने की अनुमति मिलती है. यह दो ऐनिमेशन ऑब्जेक्ट उपलब्ध कराता है, जो नेविगेटर से चलाए जाने वाले इनकमिंग और आउटगोइंग ऐनिमेशन को दिखाता है.
ट्रांज़िशन ऐनिमेशन को पसंद के मुताबिक बनाने के लिए, MaterialPageRoute
को PageRouteBuilder
से बदलें. साथ ही, जब उपयोगकर्ता HomeScreen
से QuestionScreen
पर जाता है, तो ट्रांज़िशन ऐनिमेशन को पसंद के मुताबिक बनाने के लिए, HomeScreen
को QuestionScreen
से बदलें. FadeTransition (ऐनिमेशन वाला विजेट) का इस्तेमाल करके, नई स्क्रीन को पिछली स्क्रीन के ऊपर फ़ेड इन करें.
lib/home_screen.dart
ElevatedButton(
onPressed: () {
// Show the question screen to start the game
Navigator.push(
context,
PageRouteBuilder( // NEW
pageBuilder: (context, animation, secondaryAnimation) { // NEW
return QuestionScreen(); // NEW
}, // NEW
transitionsBuilder: // NEW
(context, animation, secondaryAnimation, child) { // NEW
return FadeTransition( // NEW
opacity: animation, // NEW
child: child, // NEW
); // NEW
}, // NEW
), // NEW
);
},
child: Text('New Game'),
),
ऐनिमेशन पैकेज में, पहले से बने शानदार ऐनिमेशन इफ़ेक्ट होते हैं. जैसे, FadeThroughTransition. ऐनिमेशन पैकेज इंपोर्ट करें और FadeTransition को FadeThroughTransition विजेट से बदलें:
lib/home_screen.dart
import 'package;animations/animations.dart';
ElevatedButton(
onPressed: () {
// Show the question screen to start the game
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) {
return const QuestionScreen();
},
transitionsBuilder:
(context, animation, secondaryAnimation, child) {
return FadeThroughTransition( // NEW
animation: animation, // NEW
secondaryAnimation: secondaryAnimation, // NEW
child: child, // NEW
); // NEW
},
),
);
},
child: Text('New Game'),
),
प्रिडिक्टिव बैक ऐनिमेशन को पसंद के मुताबिक बनाना
अनुमानित तरीके से वापस जाने की सुविधा, Android की एक नई सुविधा है. इसकी मदद से, उपयोगकर्ता मौजूदा रूट या ऐप्लिकेशन पर नेविगेट करने से पहले, यह देख सकता है कि उसके पीछे क्या है. स्क्रीन पर वापस खींचने के दौरान, उपयोगकर्ता की उंगली की जगह के हिसाब से झलक दिखाने वाला ऐनिमेशन चलता है.
Flutter, सिस्टम के लेवल पर इस सुविधा को चालू करके, सिस्टम के अनुमानित बैक के साथ काम करता है. ऐसा तब होता है, जब Flutter के नेविगेशन स्टैक पर पॉप करने के लिए कोई रूट न हो. दूसरे शब्दों में, जब बैक बटन दबाने पर ऐप्लिकेशन बंद हो जाए. इस ऐनिमेशन को सिस्टम मैनेज करता है, न कि Flutter.
Flutter ऐप्लिकेशन में एक से दूसरे रूट पर जाने के दौरान, Flutter, अनुमानित तरीके से वापस जाने की सुविधा भी देता है. PredictiveBackPageTransitionsBuilder
नाम का एक खास PageTransitionsBuilder, सिस्टम के अनुमानित तरीके से वापस जाने के जेस्चर को सुनता है और जेस्चर की प्रोग्रेस के साथ पेज ट्रांज़िशन को चलाता है.
अनुमानित तरीके से वापस जाने की सुविधा, सिर्फ़ Android U और इसके बाद के वर्शन पर काम करती है. हालांकि, Flutter, वापस जाने के मूल जेस्चर और ZoomPageTransitionBuilder पर वापस आ जाएगा. ज़्यादा जानकारी के लिए, हमारी ब्लॉग पोस्ट पढ़ें. इसमें, अपने ऐप्लिकेशन में इसे सेट अप करने के तरीके के बारे में सेक्शन भी शामिल है.
अपने ऐप्लिकेशन के ThemeData कॉन्फ़िगरेशन में, PageTransitionsTheme को कॉन्फ़िगर करें, ताकि Android पर PredictiveBack का इस्तेमाल किया जा सके. साथ ही, अन्य प्लैटफ़ॉर्म पर ऐनिमेशन पैकेज से फ़ेड-थ्रू ट्रांज़िशन इफ़ेक्ट का इस्तेमाल किया जा सके:
lib/main.dart
import 'package:animations/animations.dart'; // NEW
import 'package:flutter/material.dart';
import 'home_screen.dart';
void main() {
runApp(MainApp());
}
class MainApp extends StatelessWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
useMaterial3: true,
pageTransitionsTheme: PageTransitionsTheme(
builders: {
TargetPlatform.android: PredictiveBackPageTransitionsBuilder(), // NEW
TargetPlatform.iOS: FadeThroughPageTransitionsBuilder(), // NEW
TargetPlatform.macOS: FadeThroughPageTransitionsBuilder(), // NEW
TargetPlatform.windows: FadeThroughPageTransitionsBuilder(), // NEW
TargetPlatform.linux: FadeThroughPageTransitionsBuilder(), // NEW
},
),
),
home: HomeScreen(),
);
}
}
अब Navigator.push() कॉल को MaterialPageRoute में बदला जा सकता है.
lib/home_screen.dart
ElevatedButton(
onPressed: () {
// Show the question screen to start the game
Navigator.push(
context,
MaterialPageRoute(builder: (context) { // NEW
return const QuestionScreen(); // NEW
}), // NEW
);
},
child: Text('New Game'),
),
मौजूदा सवाल बदलने के लिए, FadeThroughTransition का इस्तेमाल करना
AnimatedSwitcher विजेट, अपने बिल्डर कॉलबैक में सिर्फ़ एक ऐनिमेशन उपलब्ध कराता है. इस समस्या को हल करने के लिए, animations
पैकेज में PageTransitionSwitcher उपलब्ध कराया गया है.
lib/question_screen.dart
class QuestionCard extends StatelessWidget {
final String? question;
const QuestionCard({
required this.question,
super.key,
});
@override
Widget build(BuildContext context) {
return PageTransitionSwitcher( // NEW
layoutBuilder: (entries) { // NEW
return Stack( // NEW
alignment: Alignment.topCenter, // NEW
children: entries, // NEW
); // NEW
}, // NEW
transitionBuilder: (child, animation, secondaryAnimation) { // NEW
return FadeThroughTransition( // NEW
animation: animation, // NEW
secondaryAnimation: secondaryAnimation, // NEW
child: child, // NEW
); // NEW
}, // NEW
duration: const Duration(milliseconds: 300),
child: Card(
key: ValueKey(question),
elevation: 4,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
question ?? '',
style: Theme.of(context).textTheme.displaySmall,
),
),
),
);
}
}
OpenContainer का इस्तेमाल करना
animations
पैकेज में मौजूद OpenContainer विजेट, कंटेनर ट्रांसफ़ॉर्म ऐनिमेशन इफ़ेक्ट देता है. यह इफ़ेक्ट, दो विजेट के बीच विज़ुअल कनेक्शन बनाने के लिए बड़ा हो जाता है.
closedBuilder
से मिला विजेट शुरू में दिखता है. कंटेनर पर टैप करने या openContainer
कॉलबैक को कॉल करने पर, यह openBuilder
से मिले विजेट में बड़ा हो जाता है.
openContainer
कॉलबैक को व्यू-मॉडल से कनेक्ट करने के लिए, QuestionCard विजेट में नया पास जोड़ें और "गेम खत्म" स्क्रीन दिखाने के लिए इस्तेमाल किया जाने वाला कॉलबैक सेव करें:
lib/question_screen.dart
class QuestionScreen extends StatefulWidget {
const QuestionScreen({super.key});
@override
State<QuestionScreen> createState() => _QuestionScreenState();
}
class _QuestionScreenState extends State<QuestionScreen> {
late final QuizViewModel viewModel =
QuizViewModel(onGameOver: _handleGameOver);
VoidCallback? _showGameOverScreen; // NEW
@override
Widget build(BuildContext context) {
return ListenableBuilder(
listenable: viewModel,
builder: (context, child) {
return Scaffold(
appBar: AppBar(
actions: [
TextButton(
onPressed:
viewModel.hasNextQuestion && viewModel.didAnswerQuestion
? () {
viewModel.getNextQuestion();
}
: null,
child: const Text('Next'),
)
],
),
body: Center(
child: Column(
children: [
QuestionCard( // NEW
onChangeOpenContainer: _handleChangeOpenContainer, // NEW
question: viewModel.currentQuestion?.question, // NEW
viewModel: viewModel, // NEW
), // NEW
Spacer(),
AnswerCards(
onTapped: (index) {
viewModel.checkAnswer(index);
},
answers: viewModel.currentQuestion?.possibleAnswers ?? [],
correctAnswer: viewModel.didAnswerQuestion
? viewModel.currentQuestion?.correctAnswer
: null,
),
StatusBar(viewModel: viewModel),
],
),
),
);
},
);
}
void _handleChangeOpenContainer(VoidCallback openContainer) { // NEW
_showGameOverScreen = openContainer; // NEW
} // NEW
void _handleGameOver() { // NEW
if (_showGameOverScreen != null) { // NEW
_showGameOverScreen!(); // NEW
} // NEW
} // NEW
}
नया विजेट, GameOverScreen जोड़ें:
lib/question_screen.dart
class GameOverScreen extends StatelessWidget {
final QuizViewModel viewModel;
const GameOverScreen({required this.viewModel, super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Scoreboard(
score: viewModel.score,
totalQuestions: viewModel.totalQuestions,
),
Text(
'You Win!',
style: Theme.of(context).textTheme.displayLarge,
),
Text(
'Score: ${viewModel.score} / ${viewModel.totalQuestions}',
style: Theme.of(context).textTheme.displaySmall,
),
ElevatedButton(
child: Text('OK'),
onPressed: () {
Navigator.popUntil(context, (route) => route.isFirst);
},
),
],
),
),
);
}
}
QuestionCard विजेट में, कार्ड को ऐनिमेशन पैकेज से OpenContainer विजेट से बदलें. साथ ही, viewModel और Open Container कॉलबैक के लिए दो नए फ़ील्ड जोड़ें:
lib/question_screen.dart
class QuestionCard extends StatelessWidget {
final String? question;
const QuestionCard({
required this.onChangeOpenContainer,
required this.question,
required this.viewModel,
super.key,
});
final ValueChanged<VoidCallback> onChangeOpenContainer;
final QuizViewModel viewModel;
static const _backgroundColor = Color(0xfff2f3fa);
@override
Widget build(BuildContext context) {
return PageTransitionSwitcher(
duration: const Duration(milliseconds: 200),
transitionBuilder: (child, animation, secondaryAnimation) {
return FadeThroughTransition(
animation: animation,
secondaryAnimation: secondaryAnimation,
child: child,
);
},
child: OpenContainer( // NEW
key: ValueKey(question), // NEW
tappable: false, // NEW
closedColor: _backgroundColor, // NEW
closedShape: const RoundedRectangleBorder( // NEW
borderRadius: BorderRadius.all(Radius.circular(12.0)), // NEW
), // NEW
closedElevation: 4, // NEW
closedBuilder: (context, openContainer) { // NEW
onChangeOpenContainer(openContainer); // NEW
return ColoredBox( // NEW
color: _backgroundColor, // NEW
child: Padding( // NEW
padding: const EdgeInsets.all(16.0), // NEW
child: Text(
question ?? '',
style: Theme.of(context).textTheme.displaySmall,
),
),
);
},
openBuilder: (context, closeContainer) { // NEW
return GameOverScreen(viewModel: viewModel); // NEW
}, // NEW
),
);
}
}
8. बधाई हो
बधाई हो, आपने Flutter ऐप्लिकेशन में ऐनिमेशन इफ़ेक्ट जोड़ लिए हैं. साथ ही, Flutter के ऐनिमेशन सिस्टम के मुख्य कॉम्पोनेंट के बारे में भी जाना है. खास तौर पर, आपने ये चीज़ें सीखीं:
- ImplicitlyAnimatedWidget का इस्तेमाल करने का तरीका
- ExplicitlyAnimatedWidget का इस्तेमाल करने का तरीका
- ऐनिमेशन में कर्व और ट्वीन लागू करने का तरीका
- पहले से बने ट्रांज़िशन विजेट, जैसे कि AnimatedSwitcher या PageRouteBuilder का इस्तेमाल करने का तरीका
animations
पैकेज में पहले से मौजूद बेहतरीन ऐनिमेशन इफ़ेक्ट का इस्तेमाल करने का तरीका. जैसे, FadeThroughTransition और OpenContainer- डिफ़ॉल्ट ट्रांज़िशन ऐनिमेशन को पसंद के मुताबिक बनाने का तरीका. इसमें, Android पर प्रिडिक्टिव बैक की सुविधा जोड़ने का तरीका भी शामिल है.
आगे क्या करना है?
इनमें से कुछ कोडलैब देखें:
- Material 3 की मदद से, ऐनिमेशन वाला रिस्पॉन्सिव ऐप्लिकेशन लेआउट बनाना
- Flutter के लिए Material Motion की मदद से बेहतरीन ट्रांज़िशन बनाना
- अपने Flutter ऐप्लिकेशन को बोरिंग से खूबसूरत बनाएं
इसके अलावा, ऐनिमेशन सैंपल ऐप्लिकेशन डाउनलोड करें. इसमें ऐनिमेशन की अलग-अलग तकनीकें दिखाई गई हैं
इसके बारे में और पढ़ें
ऐनिमेशन से जुड़े ज़्यादा संसाधन पाने के लिए, flutter.dev पर जाएं:
- ऐनिमेशन के बारे में जानकारी
- ऐनिमेशन ट्यूटोरियल (ट्यूटोरियल)
- इंप्लिसिट ऐनिमेशन (ट्यूटोरियल)
- कंटेनर की प्रॉपर्टी को ऐनिमेट करना (कुकबुक)
- विजेट को धीरे-धीरे दिखाना और छिपाना (कुकबुक)
- हीरो ऐनिमेशन
- पेज के रूट ट्रांज़िशन को ऐनिमेट करना (कुकबुक)
- भौतिकी सिम्युलेशन का इस्तेमाल करके विजेट को ऐनिमेट करना (कुकबुक)
- अलग-अलग समय पर चलने वाले ऐनिमेशन
- ऐनिमेशन और मोशन विजेट (विजेट कैटलॉग)
इसके अलावा, Medium पर ये लेख पढ़ें:
- ऐनिमेशन के बारे में ज़्यादा जानें
- Flutter में कस्टम इम्प्लीसिट ऐनिमेशन
- Flutter और Flux / Redux की मदद से ऐनिमेशन मैनेज करना
- यह कैसे चुनें कि आपके लिए कौनसा Flutter ऐनिमेशन विजेट सही है?
- बिल्ट-इन साफ़ तौर पर दिखाए जाने वाले ऐनिमेशन के साथ दिशा वाले ऐनिमेशन
- इंप्लिसिट ऐनिमेशन की मदद से, Flutter ऐनिमेशन की बुनियादी बातें
- मुझे AnimatedBuilder या AnimatedWidget का इस्तेमाल कब करना चाहिए?