Flutter - Animasyon

Animasyon, herhangi bir mobil uygulamadaki karmaşık bir prosedürdür. Animasyon, karmaşıklığına rağmen kullanıcı deneyimini yeni bir düzeye çıkarır ve zengin bir kullanıcı etkileşimi sağlar. Zenginliği nedeniyle animasyon, modern mobil uygulamanın ayrılmaz bir parçası haline gelir. Flutter çerçevesi, Animasyonun öneminin farkındadır ve her türden animasyonu geliştirmek için basit ve sezgisel bir çerçeve sağlar.

Giriş

Animasyon, bir hareket yanılsaması vermek için belirli bir süre içinde bir dizi görüntüyü / resmi belirli bir sırada gösterme işlemidir. Animasyonun en önemli yönleri aşağıdaki gibidir -

  • Animasyonun iki farklı değeri vardır: Başlangıç ​​değeri ve Bitiş değeri. Animasyon Başlangıç değerinden başlar ve bir dizi ara değerden geçer ve son olarak Bitiş değerlerinde sona erer. Örneğin, bir widget'ı kaybolacak şekilde hareketlendirmek için, başlangıç ​​değeri tam opaklık ve son değer sıfır opaklık olacaktır.

  • Ara değerler, doğası gereği doğrusal veya doğrusal olmayan (eğri) olabilir ve yapılandırılabilir. Animasyonun yapılandırıldığı gibi çalıştığını anlayın. Her konfigürasyon, animasyona farklı bir his sağlar. Örneğin, bir parçacığın solması doğası gereği doğrusal olacaktır, oysa bir topun zıplaması doğası gereği doğrusal olmayacaktır.

  • Animasyon işleminin süresi, animasyonun hızını (yavaşlığı veya hızı) etkiler.

  • Animasyonu başlatmak, animasyonu durdurmak, animasyonu defalarca ayarlamak için tekrarlamak, animasyon sürecini tersine çevirmek gibi animasyon sürecini kontrol etme yeteneği,

  • Flutter'da animasyon sistemi herhangi bir gerçek animasyon yapmaz. Bunun yerine, yalnızca görüntüleri işlemek için her karede gereken değerleri sağlar.

Animasyona Dayalı Sınıflar

Flutter animasyon sistemi, Animasyon nesnelerine dayanmaktadır. Çekirdek animasyon sınıfları ve kullanımı aşağıdaki gibidir -

Animasyon

Belirli bir süre boyunca iki sayı arasında enterpolasyonlu değerler üretir. En yaygın Animasyon sınıfları şunlardır:

  • Animation<double> - iki ondalık sayı arasındaki değerleri enterpolate edin

  • Animation<Color> - iki renk arasında renklerin enterpolasyonu

  • Animation<Size> - iki boyut arasındaki boyutları enterpolate edin

  • AnimationController- Animasyonun kendisini kontrol etmek için Özel Animasyon nesnesi. Uygulama yeni bir çerçeveye hazır olduğunda yeni değerler üretir. Doğrusal tabanlı animasyonu destekler ve değer 0,0 ile 1,0 arasında başlar

controller = AnimationController(duration: const Duration(seconds: 2), vsync: this);

Burada, kontrolör animasyonu kontrol eder ve süre seçeneği animasyon işleminin süresini kontrol eder. vsync, animasyonda kullanılan kaynağı optimize etmek için kullanılan özel bir seçenektir.

Eğri Animasyon

AnimationController'a benzer, ancak doğrusal olmayan animasyonu destekler. CurvedAnimation, aşağıdaki gibi Animasyon nesnesiyle birlikte kullanılabilir -

controller = AnimationController(duration: const Duration(seconds: 2), vsync: this); 
animation = CurvedAnimation(parent: controller, curve: Curves.easeIn)

<T> ara

Animatable <T> 'den türetilmiştir ve 0 ve 1 dışındaki herhangi iki sayı arasında sayılar oluşturmak için kullanılır. Animate yöntemi kullanılarak ve gerçek Animation nesnesini ileterek Animation nesnesiyle birlikte kullanılabilir.

AnimationController controller = AnimationController( 
   duration: const Duration(milliseconds: 1000), 
vsync: this); Animation<int> customTween = IntTween(
   begin: 0, end: 255).animate(controller);
  • Tween, aşağıdaki gibi CurvedAnimation ile birlikte de kullanılabilir -

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);

Burada, denetleyici gerçek animasyon denetleyicisidir. eğri, doğrusal olmama türünü sağlar ve customTween, 0 ile 255 arasında özel aralık sağlar.

Flutter Animasyonunun iş akışı

Animasyonun iş akışı aşağıdaki gibidir -

  • StatefulWidget initState öğesinde animasyon denetleyicisini tanımlayın ve başlatın.

AnimationController(duration: const Duration(seconds: 2), vsync: this); 
animation = Tween<double>(begin: 0, end: 300).animate(controller); 
controller.forward();
  • Widget'ın durumunu değiştirmek için animasyon tabanlı dinleyici, addListener ekleyin.

animation = Tween<double>(begin: 0, end: 300).animate(controller) ..addListener(() {
   setState(() { 
      // The state that has changed here is the animation object’s value. 
   }); 
});
  • Yerleşik widget'lar, AnimatedWidget ve AnimatedBuilder bu işlemi atlamak için kullanılabilir. Her iki widget da Animasyon nesnesini kabul eder ve animasyon için gereken geçerli değerleri alır.

  • Widget'ın oluşturma işlemi sırasında animasyon değerlerini alın ve ardından orijinal değer yerine genişlik, yükseklik veya ilgili herhangi bir özellik için uygulayın.

child: Container( 
   height: animation.value, 
   width: animation.value, 
   child: <Widget>, 
)

Çalışma Uygulaması

Flutter çerçevesinde animasyon kavramını anlamak için basit bir animasyon tabanlı uygulama yazalım.

  • Android stüdyosunda yeni bir Flutter uygulaması oluşturun , product_animation_app.

  • Varlıklar klasörünü product_nav_app'den product_animation_app'e kopyalayın ve varlıkları pubspec.yaml dosyasının içine ekleyin.

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
  • Varsayılan başlangıç ​​kodunu (main.dart) kaldırın.

  • İçe aktarma ve temel ana işlevi ekleyin.

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp());
  • StatefulWidgtet'ten türetilen Uygulamam widget'ını oluşturun.

class MyApp extends StatefulWidget { 
   _MyAppState createState() => _MyAppState(); 
}
  • _MyAppState widget'ı oluşturun ve initState'i uygulayın ve varsayılan derleme yöntemine ek olarak atın.

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();
   }
}

Buraya,

  • İnitState yönteminde, bir animasyon denetleyici nesnesi (controller), bir animasyon nesnesi (animasyon) oluşturduk ve controller.forward kullanarak animasyonu başlattık.

  • Dispose yönteminde, animasyon denetleyici nesnesini (denetleyici) yerleştirdik.

  • Derleme yönteminde, yapıcı aracılığıyla MyHomePage widget'ına animasyon gönderin. Artık MyHomePage widget'ı, içeriğini canlandırmak için animasyon nesnesini kullanabilir.

  • Şimdi ProductBox widget'ını ekleyin

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()), 
                           ], 
                        )
                     )
                  )
               ]
            )
         )
      ); 
   }
}
  • Opaklık kullanarak basit solma animasyonu yapmak için yeni bir widget, MyAnimatedWidget oluşturun.

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), 
   ); 
}
  • Burada, animasyonumuzu yapmak için AniatedBuilder'ı kullandık. AnimatedBuilder, aynı anda animasyonu yaparken içeriğini oluşturan bir widget'tır. Mevcut animasyon değerini almak için bir animasyon nesnesini kabul eder. Alt widget'ın opaklığını ayarlamak için animasyon değeri, animation.value kullandık. Gerçekte, widget, opaklık konseptini kullanarak alt widget'a animasyon uygulayacaktır.

  • Son olarak, MyHomePage widget'ını oluşturun ve içeriğinden herhangi birine animasyon uygulamak için animasyon nesnesini kullanın.

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"
               ),
            ],
         )
      );
   }
}

Burada, listedeki ilk iki öğeyi canlandırmak için FadeAnimation ve MyAnimationWidget'ı kullandık. FadeAnimation, opaklık konseptini kullanarak çocuğunu canlandırmak için kullandığımız yerleşik bir animasyon sınıfıdır.

  • Kodun tamamı aşağıdaki gibidir -

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
      ), 
   ); 
}
  • Sonuçları görmek için uygulamayı derleyin ve çalıştırın. Uygulamanın ilk ve son versiyonu aşağıdaki gibidir -