بعد از خوندن این مقاله میتونید به راحتی انواع انیمیشن های زیبای فلاتر رو بسازید و بدونید که هر انیمیشن رو کی و کجا استفاده کنید.
ما برای استفاده از انیمیشن در اپلیکیشن مون میتونیم بطور کلی از دو نوع انیمیشن استفاده کنیم.
همونطور که پیداست، انیمیشن های مبتنی بر کد رو باید با کد نویسی توی برنامه پیاده سازی کرد و انیمیشن های مبتنی بر طرح هم با استفاده از پکیج های موجود که در این مقاله بهش اشاره میشه، پیاده سازی میشن.
انیمیشن های مبتنی بر کد در فلاتر بطور کلی در دو دسته زیر تقسیم میشن:
1.1. Implicit Animation
1.2. Explicit Animation
ساده ترین راه برای ساخت انیمیشن های فلاتر استفاده از انیمیشن های Implicit است. این نوع انیمیشن ها وابسته به یه مقدار هستن و فقط کافیه که یه مقدار تغییر کنه تا انیمیشن شروع بشه و بقیه کار رو خود فلاتر به عهده میگیره.
انیمیشن های Implicit نیز به دو دسته زیر تقسیم میشن:
1.1.1. AnimatedFoo
1.1.2. TweenAnimationBuilder
ویجت های آماده برای ساخت انیمیشن عبارتند از:
AnimatedContainer
AnimatedAlign
AnimatedPositioned
AnimatedOpacity
AnimatedPadding
AnimatedSize
...
کافیه تو کامپایلرتون کلمه Animated رو بزنید تا تمامی این ویجت ها رو به شما پیشنهاد بده.
تو مثال زیر قراره فقط یه مربع جابجا بشه که برای این منظور فقط از ویجت AnimatedAlign استفاده میشه.
همونطور که دیدیم، فقط مقدار _alignment به عنوان یه state در حال تغییره و ویجت AnimatedAlign هم نسبت به تغییرات این state داره واکنش نشون میده. بهمین سادگی برای بقیه ویجت های implicit میتونید همین روند رو متناسب با نیاز طراحی تون ادامه بدین. ?
⚡ کد کامل این قسمت در دارت پد
تو مثال قبلی دیدیم که تغییرات مربع بین مقدار topRight و مقدار bottomLeft بود. یعنی محدوده تغییرات به این دو مقدار محدود میشد. حالا اگه بخوایم بازه تغییرات رو بهتر مدیریت کنیم و بتونیم رنجی از تغییرات رو بین دو مقدار مشخص داشته باشیم، میتونیم از ویجت TweenAnimationBuilder استفاده کنیم که این ویجت از کلاس Tween استفاده میکنه.
کلمه Tween برگرفته شده از کلمه Between هست و یعنی بین دو چیز...
خب ما هم میخواستیم رنجی از مقادیر مختلف بین دو مقدار رو داشته باشیم، پس برای همین از کلاس Tween باید استفاده کنیم تا محدوده تغییرات رو برای انیمیشن مون مشخص کنیم. اما چطور؟?
مثال زیر رو ببینیم:
همونطور که میبینیم ویجت TweenAnimationBuilder علاوه بر duration و child دو مقدار جدید با عنوان tween و builder گرفته که در مورد tween بالا صحبت کردیم و اما مقدار builder...
متد builder مقادیر انیمیت (value) و فرزند (child) رو به ما میده که مقدار value دقیقا از نوعی هست که برای کلاس Tween در نظر گرفتیم و تو این مثال نوع double هست. این مقدار رو برای blurRadius در نظر گرفتیم؛ در واقع انیمیشن ما روی BoxShadow اتفاق میفته.
همونطور که میبینیم متد builder یه ویجت برمیگردونه. پس چرا ویجت TweenAnimationBuilder یه مقدار دیگه به نام child داره؟?
برای افزایش عملکرد برنامه!
ما میتونیم تمام ویجت هایی که به مقدار انیمیشن (یعنی مقدار value از متد builder) وابسته نیستند رو به عنوان child معرفی کنیم و تنها ویجتی که تحت تاثیر انیمیشن قرار میگیره رو توی متد builder قرار بدیم.
اینجوری باعث میشه که هربار مقدار انیمیشن (یعنی value) تغییر کنه، ویجت هایی که به عنوان child معرفی شدن rebuild نشن و فقط ویجتی که مستقیما توی متد builder هست رو rebuild کنه.
احتمالا این انیمیشن رو زیاد ندیده باشید چون خیلی کم کاربرد داره و حتی مثال بالا رو بدون این انیمیشن هم میتونستیم پیاده کنیم ?. چرا که ما فقط مقدار _shadow رو تغییر میدادیم که بدون این انیمیشن هم امکان پذیر بود و تنها کاری که انیمیشن برای ما تو مثال بالا انجام داد این بود که تغییرات blurRadius رو به نرمی با duration حدود 300 میلی ثانیه انیمیت میکرد.
⚡ کد کامل این قسمت در دارت پد
همونطور که تو تعریف انیمیشن های implicit گفتیم این انیمیشن ها وابسته به تغییر یه مقدار (state) بودن، یعنی اگه یه مقدار تغییر کرد انیمیشن شروع میشد...
سوال: اگه نخوایم وابسته به تغییرات یه state باشیم و خواستیم خودمون ریش و قیچی انیمیشن رو بدست بگیریم و هر موقع خواستیم استارت انیمیشن رو بزنیم و هر موقع خواستیم انیمیشن رو متوقف کنیم یا ترکیبی از چند انیمیشن رو بزنیم، چکار کنیم؟!!! ?
انیمیشن های Explicit این امکان رو به ما میده که بتونیم کنترل انیمیشن رو خودمون بدست بگیریم. برای این منظور کلاسی به نام AnimationController وجود داره که تو شکل زیر میبینیم:
مقادیر ورودی AnimationController:
مقدار value: مقدار اولیه برای شروع انیمیشن هست که بصورت پیشفرض برابر با مقدار lowerBound هست.
مقدار duration: خب اینم برای مدت زمان اجرای انیمیشن هست از جنس کلاس Duration.
مقدار reverseDuration: مدت زمانی است که انیمیشن بصورت معکوس بخواد اجرا شه.
مقدار lowerBound: مقدار شروع انیمیشن هست و انیمیشن کمتر از این مقدار شروع نمیشه. (بنا به نوع نیازتون اگه از کلاس Tween استفاده کنید، مقدار begin کلاس این کلاس جای مقدار lowerBound رو میگیره)
مقدار upperBound: نقطه نهایی انیمیشن هست و انیمیشن از این مقدار گذر نمیکنه. (بنا به نوع نیازتون اگه از کلاس Tween استفاده کنید، مقدار end کلاس این کلاس جای مقدار upperBound رو میگیره)
مقدار animationBehavior: این مقدار نوع رفتار انیمیشن رو بسته به مقدار ccessibilityFeatures.disableAnimations که از نوع boolean هم هست مشخص میکنه.
مقدار vsync: این مقدار از نوع کلاس TickerProvider هست. کلاس Ticker به کنترلر اجازه رو میده تا رندر فریم های انیمیشن Flutter رو دنبال بکنه.
حالا با این ویژگی میتونیم انیمیشن رو برای حالتهای زیر کنترل کنیم:
1. شروع انیمیشن با استفاده از متد forward()
2. معکوس کردن انیمیشن با استفاده از متد reverse()
3. توقف انیمیشن با استفاده از متد stop()
4. تکرار انیمیشن با استفاده از متد repeat()
5. برای برگردوندن انیمیشن به نقطه شروع (یعنی lowerBound) از متد reset() استفاده میکنیم
حالات مختلف انیمیشن:
1. حالت isAniamting: انیمیشن در حال اجراست.
2. حالت isCompleted: زمانی که انیمیشن در نقطه upperBound متوقف شده.
3. حالت isDismissed: زمانی که انیمیشن در نقطه lowerBound متوقف شده.
انواع انیمیشن های Explicit:
1.2.1. FooTransition
1.2.2. AnimatedBuilder
1.2.3. AnimatedWidget
دقیقا مثل انیمیشن های implicit برای انیمیشن های Explicit ویجت های آماده وجود داره.
AlignTransition
DecoratedBoxTransition
DefaultTextStyleTranstion
FadeTransition
PositionedTransition
RelativePositionedTransition
RotationTransition
ScaleTransition
SlideTransition
...
مقال زیر رو ببینیم:
همونطور که میبینم، ابتدا یه کنترلر برای انیمیشن مون در نظر گرفتیم که با دادن مقدار reverse: true به متد repeat() مشخص کردیم که انیمیشن ما بعد از رسیدن به نقطه پایانی، مسیری که رفته رو بصورت معکوس تا نقطه ابتدایی برگرده. مقدار tween هم مشخص میکنه که scale دایره از مقدار 1.0 تا 1.5 برابر خودش جابجا بشه. بهمین سادگی میتونیم از ویجت های آماده دیگه Explicit استفاده کنیم ?.
کد کامل این قسمت در دارت پد
اگه یادتون باشه ما تو انیمیشن های Implicit، اگه ویجت های آماده AnimatedFoo خواسته ما رو برای اون چیزی که میخواستیم ارضا نمیکردن، از TweenAnimationBuilder استفاده میکردیم. توی انیمیشن های Explicit هم اگه ویجت های آماده FooTransition خواسته ما رو نتونه ارضا کنه میتونیم از AnimatedBuilder استفاده کنیم.
خب حالا سوال پیش میاد که چه موقع FooTransiotion ها نمیتونن خواسته ما رو برآورده کنن؟ ?
شما تصور کنین میخواین روی تغییر رنگ یه container انیمیشن بزنین!
شاید همون اول کار بگین که خب نیازی به انیمیشن های Explicit نیست و میتونیم از انیمیشن های Implicit اونم از AnimatedContainer استفاده کنیم.
ولی مثلا توی طراحی انیمیشن تون نیازه که کنترل داشته باشین و بخواین تو زمان های خاص شروع بشه یا معکوسش کنین و یا هر روند دیگه ای رو برای انیمیشن تون بخواین پیاده کنین که این نوع انیمیشن رو فقط باید با Explicit ها پیاده کنین.
خب حالا چون تو Explicit ها ویجت آماده ای برای Container نداریم، پس باید با کمک AnimatedBuilder، ویجت Container مون رو به مقادیر انیمیشن مورد نظر یه جورایی وابسته کنیم.
مثال زیر رو ببینیم تا بهتر بفهمیم داستان رو:
خب دقیقا کد مثال FooTransition رو دوباره تکرار کردیم فقط با این تفاوت که یه Stack و Container اضافه شد. تو این مثال میخوایم دقیقا سایز Container دوم رو همراه با رنگش تغییر بدیم. خب برای تغییر scale که طبق مثال قبلی از ScaleTransition استفاده کردیم. اما...
اما برای تغییر رنگ Container نیاز داریم به AnimatedBuilder که توی متد builder این ویجت، Container مورد نظرمون رو میگردونه. با هر بار تغییر مقادیر انیمیشن مون، متد builder این ویجت Container ما رو rebulid میکنه.
دقیقا مثل TweenAnimationBuilder اینجا هم مقدار child رو برای AnimatedBuilder داریم تا عملکرد برنامه مون بالا بره. ولی تو این مثال ویجت خاصی نداشتیم که بخوایم بعنوان child برای AnimatedBuilder در نظر بگیریم.
مثال دیگه برای درک بهتر استفاده از AnimatedBuilder اینه که ما برای Gradient مجبوریم ازین ویجت استفاده کنیم چون ویجت GradientTransition وجود نداره.
کد کامل این قسمت در دارت پد
اگه توی کامپایلرتون بر روی اسم کلاس ScaleTransition و یا هر FooTransition ای بزنید، میبینید که این کلاس ها از AnimatedWidget ارث بری کردن و کلاس AnimatedWidget هم یه StatefuleWidget هستش.
پس ما میتونیم انیمیشن های Explicit خودمون رو با استفاده از AnimatedWidget سفارشی کنیم. مثلا میتونیم مثال بالا رو با ویجت سفارشی خودمون بسازیم:
خب ما کلاس ColorTransition خودمون رو ساختیم و جایگزین AnimatedBuilder تو کد قبلی کردیم. به همین راحتی ما یه FooTransition واسه خودمون ساختیم ?.
کد این قسمت در دارت پد
این انیمیشن ها در قالب بسته هایی به برنامه شما تزریق میشن و میتونید ازشون استفاده کنید.
2.1. Lottie
2.2. Rive
1. Code-based VS Drawing-based??
اگه انیمیشن تون بیشتر شبیه یه طرحه، بهتره از انیمیشن های مبتنی بر طرح استفاده کنید.
اگه انیمیشن تون بیشتر مربوط میشه به چیدمان داخلی برنامه (سایز و ویژگی ویجت ها و ...) از انیمیشن های Implicit یا Explicit استفاده کنید.
2. Explicit VS Implicit? ?
اگه انیمیشن تون دارای ویژگی های زیر هستش بهتره از Explicit استفاده کنید:
3. Built-in VS Custom Widgets
و در آخر هم احتمالا بین استفاده از ویجت های آماده یا همون Built-in یعنی AnimtedFoo/FooTransition و کلاس های Custom یعنی TweenAnimationBuildr/AnimatedBuilder/AnimatedWidget گیج بشین...
که این هم کاری نداره...
تنها کافیه ببینید که اون ویژگی ای که میخواین انیمیتش کنید، داخل ویجت های آماده AnimatedFoo یا FooTransition هست یا نه... اگه نبود میرین سراغ استفاده از Custom Widget ها. به همین راحتی?.
حالا برو انیمیشن های خفن بزن و از قدرت فلاتر توی پیاده سازی انیمیشن ها لذت ببر ??