انیمیشن در فلاتر – Flutter
انیمیشن یک فرآیند پیچیده در هر برنامه موبایل است. با وجود پیچیدگی ، انیمیشن تجربه کاربر را به سطح جدیدی ارتقا داده و تعامل کاربر غنی را فراهم می کند. به دلیل غنای آن ، انیمیشن به بخشی جدایی ناپذیر از برنامه مدرن موبایل تبدیل می شود. فریمورک Flutter اهمیت انیمیشن را تشخیص می دهد و یک چارچوب ساده و شهودی برای توسعه انواع انیمیشن ها فراهم می کند.
مقالات
مقدمه
انیمیشن فرآیندی است برای نشان دادن یک سری از تصاویر / تصویر به ترتیب خاص در یک مدت تا کاربر واقعا تصور کند تصاویر حرکت می کنند. مهمترین جنبه های انیمیشن به شرح زیر است –
- انیمیشن دو مقدار مشخص دارد: مقدار Start و مقدار End. انیمیشن از مقدار Start شروع می شود و از یک سری مقادیر میانی عبور می کند و سرانجام در مقادیر End خاتمه می یابد. به عنوان مثال ، برای تحریک کردن یک ویجت برای محو شدن ، مقدار اولیه opacity کامل و مقدار نهایی opacity صفر خواهد بود.
- مقادیر میانی ممکن است از نظر خطی یا غیر خطی (منحنی) بوده و قابل تنظیم باشند. انیمیشن همانطور که پیکربندی شده است کار می کند. هر پیکربندی احساس متفاوتی را به انیمیشن ارائه می دهد. به عنوان مثال ، برای محو شدن یک ویجت مقدار اولیه full opacity و مقدار نهایی zero opacity می باشد
- مدت زمان پویانمایی روی سرعت (کندی یا سرعت) انیمیشن تأثیر می گذارد.
- امکان کنترل فرایند انیمیشن مانند شروع انیمیشن ، متوقف کردن انیمیشن ، تکرار انیمیشن برای تنظیم تعداد دفعات ، معکوس کردن روند انیمیشن و غیره ،
- در فلاتر ، سیستم انیمیشن هیچ انیمیشن واقعی انجام نمی دهد. در عوض ، فقط مقادیر مورد نیاز در هر فریم را برای ارائه تصاویر فراهم می کند.
کلاس های مبتنی بر انیمیشن فلاتر
سیستم انیمیشن فلوتر مبتنی بر اشیاء انیمیشن است. کلاس های اصلی انیمیشن و کاربرد آن به شرح زیر است –
Animation
مقادیر درون یابی شده بین دو عدد را در مدت زمان معین ایجاد می کند. رایج ترین کلاس های animation –
- Animation<double> – مقادیر درون یابی بین دو عدد اعشاری
- Animation<Color> – بین دو رنگ ،رنگ را درج کنید
- Animation<Size> – اندازه های درون را بین دو اندازه تغییر دهید
- AnimationController – آبجکت ویژه انیمیشن برای کنترل خود انیمیشن. هر زمان که برنامه برای یک frame جدید آماده باشد ، مقادیر جدیدی تولید می کند. این انیمیشن مبتنی بر خطی را پشتیبانی می کند و مقدار آن از 0.0 تا 1.0 شروع می شود.
1 |
controller = AnimationController(duration: const Duration(seconds: 2), vsync: this); |
در اینجا ، controller انیمیشن را کنترل می کند و duration طول فرایند انیمیشن را کنترل می کند. vsync گزینه ویژه ای است که برای بهینه سازی منابع مورد استفاده در انیمیشن مورد استفاده قرار می گیرد.
CurvedAnimation
شبیه به AnimationController اما از انیمیشن غیرخطی پشتیبانی می کند. CurvedAnimation را می توان به همراه شیء Animation به صورت زیر استفاده کرد –
1 2 |
controller = AnimationController(duration: const Duration(seconds: 2), vsync: this); animation = CurvedAnimation(parent: controller, curve: Curves.easeIn) |
Tween<T>
مشتق شده از Animatable <T> و برای تولید اعداد بین هر دو عدد به غیر از 0 و 1. استفاده می شود. با استفاده از متد animate و پاس دادن شیء Animation واقعی می توان از آن استفاده کرد.
1 2 3 4 |
AnimationController controller = AnimationController( duration: const Duration(milliseconds: 1000), vsync: this); Animation<int> customTween = IntTween( begin: 0, end: 255).animate(controller); |
Tween همچنین می تواند به همراه زیر CurvedAnimation استفاده شود –
1 2 3 4 |
AnimationController controller = AnimationController( duration: const Duration(milliseconds: 500), vsync: this); final Animation curve = CurvedAnimation(parent: controller, curve: Curves.easeOut); Animation<int> customTween = IntTween(begin: 0, end: 255).animate(curve); |
در اینجا ، controller کنترلر واقعی انیمیشن است. منحنی نوع غیر خطی را ارائه می دهد و customTween دامنه سفارشی از 0 تا 255 را فراهم می کند.
جریان کار انیمیشن Flutter
جریان کار انیمیشن به شرح زیر است –
- Controller انیمیشن را در startState of StatefulWidget تعریف و شروع کنید.
1 2 3 |
AnimationController(duration: const Duration(seconds: 2), vsync: this); animation = Tween<double>(begin: 0, end: 300).animate(controller); controller.forward(); |
اضافه کردن انیمیشن مبتنی بر listener ،addListener برای تغییر وضعیت listener استفاده می شود.
1 2 3 4 5 |
animation = Tween<double>(begin: 0, end: 300).animate(controller) ..addListener(() { setState(() { // The state that has changed here is the animation object’s value. }); }); |
- Build-in، AnimatedWidget و AnimatedBuilder را می توان برای پرش از این فرآیند استفاده کرد. هر دو ویجت شی انیمیشن را می پذیرند و مقادیر فعلی مورد نیاز انیمیشن را دریافت می کنند.
- مقادیر انیمیشن را در طی مراحل ساخت ویجت بدست آورید و سپس به جای مقدار اصلی ، آن را برای width ، height یا هر خاصیت مربوطه اعمال کنید.
1 2 3 4 5 |
child: Container( height: animation.value, width: animation.value, child: <Widget>, ) |
ایجاد یک برنامه کاربردی
بگذارید یک اپلیکیشن ساده مبتنی بر انیمیشن بنویسیم تا مفهوم انیمیشن را در فریمورک Flutter را بهتر درک کنیم.
- یک برنامه جدید Flutter را در studio Android ایجاد کنید ، product_animation_app.
- پوشه assets را از product_nav_app به product_animation_app کپی کرده و assets موجود در پرونده pubspec.yaml را اضافه کنید.
1 2 3 4 5 6 7 8 |
flutter: assets: - assets/appimages/floppy.png - assets/appimages/iphone.png - assets/appimages/laptop.png - assets/appimages/pendrive.png - assets/appimages/pixel.png - assets/appimages/tablet.png |
- کد startup پیش فرض (main.dart) را حذف کنید.
- import و فانکشن اصلی را اضافه کنید.
1 2 |
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); |
ویجت MyApp را که از StatefulWidgtet گرفته شده است ، ایجاد کنید.
1 2 3 |
class MyApp extends StatefulWidget { _MyAppState createState() => _MyAppState(); } |
ویجت _MyAppState را ایجاد کرده و initState را پیاده سازی کنید
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin { Animation<double> animation; AnimationController controller; @override void initState() { super.initState(); controller = AnimationController( duration: const Duration(seconds: 10), vsync: this ); animation = Tween<double>(begin: 0.0, end: 1.0).animate(controller); controller.forward(); } // This widget is the root of your application. @override Widget build(BuildContext context) { controller.forward(); return MaterialApp( title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue,), home: MyHomePage(title: 'Product layout demo home page', animation: animation,) ); } @override void dispose() { controller.dispose(); super.dispose(); } } |
اینجا،
- در متد initState ، یک شی کنترلر انیمیشن (controller) ، یک شیء انیمیشن (animation) ایجاد کرده ایم و انیمیشن را با استفاده از Controler.forward شروع کرده ایم.
- در روش دفع ، ما یک کنترلر انیمیشن (controller) را دور ریخته ایم.
- در متد build ، انیمیشن را از طریق constructor به ویجت MyHomePage ارسال کنید. اکنون ویجت MyHomePage می تواند از شیء animation برای متحرک کردن محتوای خود استفاده کند.
- اکنون ویجت ProductBox را اضافه کنید
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
class ProductBox extends StatelessWidget { ProductBox({Key key, this.name, this.description, this.price, this.image}) : super(key: key); final String name; final String description; final int price; final String image; Widget build(BuildContext context) { return Container( padding: EdgeInsets.all(2), height: 140, child: Card( child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ Image.asset("assets/appimages/" + image), Expanded( child: Container( padding: EdgeInsets.all(5), child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ Text(this.name, style: TextStyle(fontWeight: FontWeight.bold)), Text(this.description), Text("Price: " + this.price.toString()), ], ) ) ) ] ) ) ); } } |
برای انجام انیمیشن ساده fade با استفاده از opacity ، یک ویجت جدید ، MyAnimatedWidget ایجاد کنید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class MyAnimatedWidget extends StatelessWidget { MyAnimatedWidget({this.child, this.animation}); final Widget child; final Animation<double> animation; Widget build(BuildContext context) => Center( child: AnimatedBuilder( animation: animation, builder: (context, child) => Container( child: Opacity(opacity: animation.value, child: child), ), child: child), ); } |
- در اینجا ، ما از AniatedBuilder برای انجام انیمیشن خود استفاده کرده ایم. AnimatedBuilder یک ویجت است که ضمن انجام انیمیشن در همان زمان ، محتوای خود را ایجاد می کند. این یک شیء animation را می پذیرد تا value یا مقدار انیمیشن فعلی را بدست آورد. ما برای تعیین opacity ویجت فرزند از value انیمیشن ، animation.value استفاده کرده ایم. در واقع ، widget ویجت فرزندا را با استفاده از مفهوم opacity ، نمایش میدهد.
- در آخر ، ویجت MyHomePage را ایجاد کرده و از شیء animation برای متحرک کردن هر یک از محتوای آن استفاده کنید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
class MyHomePage extends StatelessWidget { MyHomePage({Key key, this.title, this.animation}) : super(key: key); final String title; final Animation<double> animation; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("Product Listing")),body: ListView( shrinkWrap: true, padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), children: <Widget>[ FadeTransition( child: ProductBox( name: "iPhone", description: "iPhone is the stylist phone ever", price: 1000, image: "iphone.png" ), opacity: animation ), MyAnimatedWidget(child: ProductBox( name: "Pixel", description: "Pixel is the most featureful phone ever", price: 800, image: "pixel.png" ), animation: animation), ProductBox( name: "Laptop", description: "Laptop is most productive development tool", price: 2000, image: "laptop.png" ), ProductBox( name: "Tablet", description: "Tablet is the most useful device ever for meeting", price: 1500, image: "tablet.png" ), ProductBox( name: "Pendrive", description: "Pendrive is useful storage medium", price: 100, image: "pendrive.png" ), ProductBox( name: "Floppy Drive", description: "Floppy drive is useful rescue storage medium", price: 20, image: "floppy.png" ), ], ) ); } } |
در اینجا ، ما از FadeAnimation و MyAnimationWidget برای متحرک کردن دو item اول در لیست استفاده کرده ایم. FadeAnimation یک کلاس animation داخلی است که ما با استفاده از opacity فرزند آن را متحرک کرده ایم
- کد کامل به صورت زیر می باشد –
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatefulWidget { _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin { Animation<double> animation; AnimationController controller; @override void initState() { super.initState(); controller = AnimationController( duration: const Duration(seconds: 10), vsync: this); animation = Tween<double>(begin: 0.0, end: 1.0).animate(controller); controller.forward(); } // This widget is the root of your application. @override Widget build(BuildContext context) { controller.forward(); return MaterialApp( title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue,), home: MyHomePage(title: 'Product layout demo home page', animation: animation,) ); } @override void dispose() { controller.dispose(); super.dispose(); } } class MyHomePage extends StatelessWidget { MyHomePage({Key key, this.title, this.animation}): super(key: key); final String title; final Animation<double> animation; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("Product Listing")), body: ListView( shrinkWrap: true, padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), children: <Widget>[ FadeTransition( child: ProductBox( name: "iPhone", description: "iPhone is the stylist phone ever", price: 1000, image: "iphone.png" ), opacity: animation ), MyAnimatedWidget( child: ProductBox( name: "Pixel", description: "Pixel is the most featureful phone ever", price: 800, image: "pixel.png" ), animation: animation ), ProductBox( name: "Laptop", description: "Laptop is most productive development tool", price: 2000, image: "laptop.png" ), ProductBox( name: "Tablet", description: "Tablet is the most useful device ever for meeting", price: 1500, image: "tablet.png" ), ProductBox( name: "Pendrive", description: "Pendrive is useful storage medium", price: 100, image: "pendrive.png" ), ProductBox( name: "Floppy Drive", description: "Floppy drive is useful rescue storage medium", price: 20, image: "floppy.png" ), ], ) ); } } class ProductBox extends StatelessWidget { ProductBox({Key key, this.name, this.description, this.price, this.image}) : super(key: key); final String name; final String description; final int price; final String image; Widget build(BuildContext context) { return Container( padding: EdgeInsets.all(2), height: 140, child: Card( child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ Image.asset("assets/appimages/" + image), Expanded( child: Container( padding: EdgeInsets.all(5), child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[ Text( this.name, style: TextStyle( fontWeight: FontWeight.bold ) ), Text(this.description), Text( "Price: " + this.price.toString() ), ], ) ) ) ] ) ) ); } } class MyAnimatedWidget extends StatelessWidget { MyAnimatedWidget({this.child, this.animation}); final Widget child; final Animation<double> animation; Widget build(BuildContext context) => Center( child: AnimatedBuilder( animation: animation, builder: (context, child) => Container( child: Opacity(opacity: animation.value, child: child), ), child: child ), ); } |
اپلیکیشن را کامپایل و اجرا کنید تا نتیجه را ببینید.
مطالب زیر را حتما مطالعه کنید
آموزش فلاتر – Flutter
ابزار توسعه فلاتر – Flutter
تبدیل اپلیکیشن فلاتر به اندروید و IOS
تست کردن در فلاتر – Flutter testing
ترجمه اپلیکیشن ها در فلاتر – Flutter
کار با دیتابیس در فلاتر -Flutter
1 دیدگاه
به گفتگوی ما بپیوندید و دیدگاه خود را با ما در میان بگذارید.
استاد خيلي كارت درسته بازم چيزاي ديگه بزار♥(: