Flutter - Animasi
Animasi adalah prosedur yang rumit dalam aplikasi seluler apa pun. Terlepas dari kerumitannya, Animasi meningkatkan pengalaman pengguna ke tingkat yang baru dan menyediakan interaksi pengguna yang kaya. Karena kekayaannya, animasi menjadi bagian integral dari aplikasi seluler modern. Kerangka kerja Flutter mengakui pentingnya Animasi dan menyediakan kerangka kerja yang sederhana dan intuitif untuk mengembangkan semua jenis animasi.
pengantar
Animasi adalah proses menampilkan rangkaian gambar / gambar dengan urutan tertentu dalam durasi tertentu untuk memberikan ilusi gerakan. Aspek terpenting dari animasi adalah sebagai berikut -
Animasi memiliki dua nilai berbeda: Nilai awal dan Nilai akhir. Animasi dimulai dari nilai Mulai dan melewati serangkaian nilai antara dan akhirnya berakhir di nilai Akhir. Misalnya, untuk menganimasikan widget agar menghilang, nilai awalnya adalah opasitas penuh dan nilai akhirnya adalah opasitas nol.
Nilai antara dapat berupa linier atau non-linier (kurva) dan dapat dikonfigurasi. Pahami bahwa animasi berfungsi seperti yang dikonfigurasi. Setiap konfigurasi memberikan nuansa yang berbeda pada animasi. Misalnya, memudarkan widget akan bersifat linier sedangkan memantul bola akan bersifat non-linier.
Durasi proses animasi mempengaruhi kecepatan (kelambatan atau kecepatan luntur) animasi.
Kemampuan untuk mengontrol proses animasi seperti memulai animasi, menghentikan animasi, mengulang animasi untuk mengatur berapa kali, membalik proses animasi, dll.,
Di Flutter, sistem animasi tidak melakukan animasi nyata. Sebaliknya, ini hanya memberikan nilai yang diperlukan di setiap bingkai untuk merender gambar.
Kelas Berbasis Animasi
Sistem animasi Flutter didasarkan pada objek Animation. Kelas animasi inti dan penggunaannya adalah sebagai berikut -
Animasi
Menghasilkan nilai interpolasi antara dua angka selama durasi tertentu. Kelas Animasi yang paling umum adalah -
Animation<double> - menginterpolasi nilai antara dua angka desimal
Animation<Color> - interpolasi warna antara dua warna
Animation<Size> - ukuran interpolasi antara dua ukuran
AnimationController- Objek Animasi Khusus untuk mengontrol animasi itu sendiri. Ini menghasilkan nilai baru setiap kali aplikasi siap untuk bingkai baru. Ini mendukung animasi berbasis linier dan nilainya mulai dari 0,0 hingga 1,0
controller = AnimationController(duration: const Duration(seconds: 2), vsync: this);
Di sini, pengontrol mengontrol opsi animasi dan durasi mengontrol durasi proses animasi. vsync adalah opsi khusus yang digunakan untuk mengoptimalkan sumber daya yang digunakan dalam animasi.
CurvedAnimation
Mirip dengan AnimationController tetapi mendukung animasi non-linier. CurvedAnimation dapat digunakan bersama dengan objek Animation seperti di bawah ini -
controller = AnimationController(duration: const Duration(seconds: 2), vsync: this);
animation = CurvedAnimation(parent: controller, curve: Curves.easeIn)
Tween <T>
Berasal dari Animatable <T> dan digunakan untuk menghasilkan angka antara dua angka selain 0 dan 1. Ini dapat digunakan bersama dengan objek Animation dengan menggunakan metode animate dan meneruskan objek Animation yang sebenarnya.
AnimationController controller = AnimationController(
duration: const Duration(milliseconds: 1000),
vsync: this); Animation<int> customTween = IntTween(
begin: 0, end: 255).animate(controller);
Tween juga dapat digunakan bersama CurvedAnimation seperti di bawah ini -
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);
Di sini, pengontrol adalah pengontrol animasi yang sebenarnya. curve menyediakan jenis non-linearitas dan customTween menyediakan rentang khusus dari 0 hingga 255.
Alur kerja Animasi Flutter
Alur kerja animasinya adalah sebagai berikut -
Tentukan dan mulai pengontrol animasi di initState dari StatefulWidget.
AnimationController(duration: const Duration(seconds: 2), vsync: this);
animation = Tween<double>(begin: 0, end: 300).animate(controller);
controller.forward();
Tambahkan pendengar berbasis animasi, addListener untuk mengubah status widget.
animation = Tween<double>(begin: 0, end: 300).animate(controller) ..addListener(() {
setState(() {
// The state that has changed here is the animation object’s value.
});
});
Widget built-in, AnimatedWidget dan AnimatedBuilder dapat digunakan untuk melewati proses ini. Kedua widget menerima objek Animasi dan mendapatkan nilai saat ini yang diperlukan untuk animasi.
Dapatkan nilai animasi selama proses build widget, lalu terapkan untuk lebar, tinggi, atau properti apa pun yang relevan, bukan nilai aslinya.
child: Container(
height: animation.value,
width: animation.value,
child: <Widget>,
)
Aplikasi Kerja
Mari kita tulis aplikasi berbasis animasi sederhana untuk memahami konsep animasi dalam framework Flutter.
Buat aplikasi Flutter baru di studio Android, product_animation_app.
Salin folder aset dari product_nav_app ke product_animation_app dan tambahkan aset di dalam file pubspec.yaml.
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
Hapus kode startup default (main.dart).
Tambahkan impor dan fungsi utama dasar.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
Buat widget MyApp berasal dari StatefulWidgtet.
class MyApp extends StatefulWidget {
_MyAppState createState() => _MyAppState();
}
Buat widget _MyAppState dan implementasikan initState serta buang selain metode build default.
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();
}
}
Sini,
Dalam metode initState, kita telah membuat objek pengontrol animasi (pengontrol), objek animasi (animasi) dan memulai animasi menggunakan controller.forward.
Dalam metode pembuangan, kita telah membuang objek pengontrol animasi (pengontrol).
Dalam metode build, kirim animasi ke widget MyHomePage melalui konstruktor. Sekarang, widget MyHomePage dapat menggunakan objek animasi untuk menganimasikan kontennya.
Sekarang, tambahkan widget ProductBox
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()),
],
)
)
)
]
)
)
);
}
}
Buat widget baru, MyAnimatedWidget untuk melakukan animasi fade sederhana menggunakan opacity.
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),
);
}
Di sini, kami telah menggunakan AniatedBuilder untuk melakukan animasi kami. AnimatedBuilder adalah widget yang membangun kontennya sambil melakukan animasi pada saat yang bersamaan. Ini menerima objek animasi untuk mendapatkan nilai animasi saat ini. Kami telah menggunakan nilai animasi, animation.value untuk mengatur opasitas widget anak. Akibatnya, widget akan menganimasikan widget anak menggunakan konsep opasitas.
Terakhir, buat widget MyHomePage dan gunakan objek animasi untuk menganimasikan semua kontennya.
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"
),
],
)
);
}
}
Di sini, kami telah menggunakan FadeAnimation dan MyAnimationWidget untuk menganimasikan dua item pertama dalam daftar. FadeAnimation adalah kelas animasi bawaan, yang kami gunakan untuk menganimasikan anaknya menggunakan konsep opasitas.
Kode lengkapnya adalah sebagai berikut -
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
),
);
}
Kompilasi dan jalankan aplikasi untuk melihat hasilnya. Versi awal dan akhir aplikasi adalah sebagai berikut -