Last Updated on July 19, 2022 by
Mencari coding Flutter animation yang lengkap? Yuk langsung simak tutorial belajar flutter animation berikut ini sampai tuntas!
Seri belajar flutter animation kali ini akan mengajak Anda menguasai dua point berikut:
- Cara menggunakan kelas-kelas dasar dari pustaka animasi untuk menambahkan efek animasi pada sebuah widget.
- Momen yang tepat untuk menggunakan AnimatedWidget dan AnimatedBuilder.
Anda juga akan belajar bagaimana cara membuat animasi yang “eksplisit” dengan Flutter.
Setelah memahami beberapa konsep, kelas dan metode esensial dari perpustakaan animasi, kami akan menunjukkan 5 contoh pembuatan animation Flutter yang dibangun di atas satu sama lain. Dari sinilah Anda akan melihat berbagai sisi pustaka animasi Flutter secara mendalam.
Flutter SDK juga menyediakan animasi eksplisit bawaan, seperti FadeTransition, SizeTransition, dan SlideTransition. Animasi sederhana ini diaktifkan oleh pengaturan pada titik awal dan akhir pemrograman. Mereka lebih mudah diterapkan daripada animasi eksplisit khusus atau custom.
Table of Contents
Belajar Flutter Animation : Konsep dan Kelas Esensial
Poin penting untuk diingat :
- Animasi – merupakan kelas inti di perpustakaan animation Flutter– menginterpolasi nilai yang digunakan untuk memandu jalannya sebuah animasi.
- Objek Animasi mengetahui status animasi saat ini (misalnya, apakah animasi mulai berjalan, berhenti, atau bergerak maju atau mundur), tetapi komponen ini tidak tahu apapun terkait bentuk yang muncul di layar.
- AnimationController dipakai untuk mengelola Animasi.
- CurvedAnimation mendefinisikan perkembangan desain dalam bentuk kurva non-linier.
- Tween menginterpolasi antara rentang data seperti yang digunakan oleh objek yang dianimasikan. Misalnya, Tween mungkin mendefinisikan interpolasi dari merah ke biru, atau dari 0 hingga 255.
- Gunakan Listeners dan StatusListeners untuk memantau perubahan status animasi.
Sistem animasi di Flutter didasarkan pada objek Animasi yang Anda ketik. Terdapat dua cara bagi Widget untuk menggabungkan animasi secara langsung ke fungsi build mereka.
Pertama, Widget membaca nilai animasi saat ini dan mendengarkan perubahan statusnya. Atau kedua, mereka memakai sebuah animasi sebagai dasar untuk animasi yang lebih rumit, dan yang mereka teruskan ke Widget lain.
Flutter Animation<double>
Objek flutter animation tidak tahu apa-apa terkait bentuk yang muncul di layar komputer. Animasi hanya sebatas kelas abstrak yang memahami nilai dan statusnya saat ini (selesai atau diberhentikan). Salah satu jenis animasi yang umum digunakan adalah Animation<double>.
Objek animasi secara berurutan menghasilkan angka yang diinterpolasi antara dua nilai selama durasi tertentu. Output dari objek Animasi bisa berupa angka linear, kurva, fungsi langkah, atau pemetaan lain sesuai rancangan Anda.
Animasi pun dapat bergerak secara terbalik atau tiba-tiba berputar arah di tengah perjalanan, tergantung pada bagaimana cara Anda mengendalikannya.
Lebih jauh lagi, sebuah animasi bisa menginterpolasi varian lain selain double, misalnya Animation<Color> atau Animation<Size>.
Setiap objek animasi memiliki status, yang mana nilainya selalu tersedia dalam anggota .value.
Selain tidak tahu akan rupa yang muncul di layar, objek animasi turut tidak tahu-menahu tentang rendering atau fungsi build().
CurvedAnimation
CurvedAnimation mendefinisikan progres animasi dalam bentuk kurva non linear. Adapun coding CurvedAnimation adalah:
animation = CurvedAnimation(parent: controller, curve: Curves.easeIn);
Catatan: kelas Curves dapat mendefinisikan banyak kurva yang sering digunakan, ataupun kurva custom yang Anda susun sendiri.
Contoh coding CurvedAnimation:
import 'dart:math'; class ShakeCurve extends Curve { @override double transform(double t) => sin(t * pi * 2); }
Telusuri dokumentasi Curves untuk mendapatkan daftar lengkap konstanta kurva Flutter (dengan pratinjau visual).
CuverdAnimation dan AnimationController (akan dijelaskan pada bagian selanjutnya) merupakan bagian dari Animation<double>, jadi Anda bisa melewati keduanya secara bergantian.
Khusus untuk CurvedAnimation, ia dapat menjadi pembungkus objek yang dimodifikasi. Kita tidak membuat subclass AnimationController untuk menerapkan suatu kurva.
AnimationController
AnimationController adalah objek animation Flutter khusus yang menghasilkan nilai baru setiap kali komputer siap untuk mengolah bingkai baru.
Secara default, AnimationController menghasilkan angka dari 0,0 hingga 1,0 secara linier dalam durasi tertentu. Sebagai contoh, coding berikut ini bisa untuk membuat objek animasi Flutter, tetapi tidak untuk menjalankannya:
controller = AnimationController(duration: const Duration(seconds: 2), vsync: this);
AnimationController diturunkan dari Animation<double>, sehingga dapat digunakan di mana pun objek animation diperlukan. Namun, AnimationController memiliki metode tambahan untuk mengontrol animasi.
Misalnya, Anda memulai animasi dengan metode .forward(). Kemudian, serangkaian angka akan dihasilkan oleh metode ini – biasanya 60 angka per detik – dan mereka “terikat” ke refresh layar.
Setelah semua angka sukses dibuat, setiap objek animasi kini bisa memanggil objek Listener yang terlampir di pustaka. Cek juga bagian RepaintBoundary terkait cara membuat daftar tampilan kustom dari setiap anak animasi.
Saat membuat AnimationController, Anda akan meneruskan argumen vsync. Kehadiran vsync mencegah animasi di luar layar menghabiskan sumber daya yang tidak perlu.
Anda dapat menggunakan objek stateful sebagai vsync dengan menambahkan SingleTickerProviderStateMixin ke definisi kelas.
Catatan: Dalam beberapa kasus, sebuah posisi bisa melebihi rentang 0.0-1.0 dari AnimationController. Misalnya, fungsi fling() memungkinkan Anda untuk memberikan kecepatan, gaya, dan posisi (melalui objek Force). Posisinya bias berupa apa saja dan bisa di luar kisaran 0,0 hingga 1,0.
CurvedAnimation juga dapat melebihi rentang 0,0 hingga 1,0, bahkan ketika AnimationController tidak. Output dari CurvedAnimation dapat memiliki jangkauan yang lebih luas daripada input-nya, bergantung dari jenis kurva yang dipilih digunakan.
Misalnya, kurva elastis seperti Curves.elasticIn secara signifikan men-overshoots atau undershoots rentang nilai default.
Tween
Secara default, objek AnimationController berkisar dari 0,0 hingga 1,0. Namun kalau Anda memerlukan rentang yang berbeda, atau menggunakan tipe data lain, maka konfigurasi animasi dengan Tween untuk menginterpolasinya ke rentang atau tipe data custom.
Misalnya, coding Tween berikut mengubah dari -200.0 ke 0.0:
tween = Tween<double>(begin: -200, end: 0);
Tween adalah stateless object (objek tanpa status) yang hanya bekerja di awal dan akhir. Satu-satunya tugas Tween adalah menentukan pemetaan dari rentang input ke rentang output. Rentang input umumnya 0,0 hingga 1,0, tetapi itu bukanlah syarat wajib dalam coding Tween.
Tween diturunkan dari Animatable<T>, bukan Animation<T>. Animatable, seperti Animation, tidak harus menghasilkan output double. Misalnya, ColorTween merinci progresi percampuran dua warna dalam animasi.
colorTween = ColorTween(begin: Colors.transparent, end: Colors.black54);
Objek Tween tidak menyimpan status apa pun. Sebaliknya, ia menyediakan metode evaluate(Animation<double> animation) yang menerapkan fungsi pemetaan ke nilai animasi saat ini.
Nilai objek animasi saat ini dapat ditemukan dalam metode .value. Fungsi evaluasi juga melaksanakan sejumlah fungsi pemeliharaan sistem animasi, seperti memastikan bahwa titik awal dan akhir dikembalikan seperti semula saat nilai animasi mencapai 0,0 dan 1,0.
Tween.animate
Untuk menggunakan objek Tween, panggil animate() pada Tween, lalu teruskan ke objek controller. Misalnya, contoh kode berikut menghasilkan nilai integer dari 0 hingga 255 selama 500 ms:
AnimationController controller = AnimationController( duration: const Duration(milliseconds: 500), vsync: this);
Animation<int> alpha = IntTween(begin: 0, end: 255).animate(controller);
Catatan: Metode animate() mengembalikan Animation, bukan Animatable.
Contoh di bawah ini memperlihatkan pemakaian controller, curve dan Tween:
AnimationController controller = AnimationController( duration: const Duration(milliseconds: 500), vsync: this); final Animation<double> curve = CurvedAnimation(parent: controller, curve: Curves.easeOut); Animation<int> alpha = IntTween(begin: 0, end: 255).animate(curve);
Notifikasi Animasi
Objek Animasi dapat memiliki Listeners dan StatusListeners, yang didefinisikan dengan addListener() dan addStatusListener().
Listener dipanggil setiap kali nilai animasi berubah. Fungsi umum dari Listener adalah memanggil setState() untuk mengulang pembangunan (rebuild).
StatusListener dipanggil ketika animasi dimulai, berakhir, bergerak maju, atau bergerak mundur, seperti yang didefinisikan oleh AnimationStatus.
Contoh di bagian selanjutnya akan memperlihatkan pemakaian metode addListener(), dan memantau kemajuan animasi Flutter dengan addStatusListener().
5 Contoh Flutter Animation
Setelah memahami konsep dan elemen dasar, berikutnya mari simak 5 contoh coding animasi di Flutter berikut ini:
Rendering Animasi di Flutter
Poin yang akan dibahas:
- Menambahkan animasi sederhana ke Widget memakai addListener() dan setState().
- Menggunakan fungsi addListener() untuk memanggil setState() di setiap kali Animation menciptakan series angka baru.
- Mendefinisikan AnimationController dengan parameter bersyarat vsync.
- Memahami arti dan fungsi bagian “. .” dari sintaksis “. . addListener” – bentuk kode ini juga dikenal dengan nama cascade notation
- Membuat kelas yang rahasia (private) dengan membubuhkan garis bawah (_) di awal nama.
Sejauh ini Anda sudah mempelajari cara menghasilkan angka animasi berurutan dari waktu ke waktu, namun, masih belum ada hal yang kita render ke layar.
Untuk merender animasi di Flutter, Anda harus menyimpan objek animasi sebagai bagian dari Widget. Kemudian gunakan nilai-nilainya untuk menentukan cara terbaik menggambar gerakan animasi.
Berikut adalah coding dari aplikasi untuk menggambar logo Flutter tanpa animasi:
import 'package:flutter/material.dart'; void main() => runApp(const LogoApp()); class LogoApp extends StatefulWidget { const LogoApp({super.key}); @override State<LogoApp> createState() => _LogoAppState(); } class _LogoAppState extends State<LogoApp> { @override Widget build(BuildContext context) { return Center( child: Container( margin: const EdgeInsets.symmetric(vertical: 10), height: 300, width: 300, child: const FlutterLogo(), ), ); } }
Sumber app : animate0
Kemudian, contoh di bawah memperlihatkan modifikasi dari kode di atas untuk menganimasikan logo supaya “bergerak tumbuh” dari nol menjadi penuh (full size). Saat mendefinisikan AnimationController, Anda juga harus meneruskan objek vsync.
{animate0 → animate1}/lib/main.dart Viewed @@ -9,16 +9,39 @@ 9 9 State<LogoApp> createState() => _LogoAppState(); 10 10 } 11 - class _LogoAppState extends State<LogoApp> { 11 + class _LogoAppState extends State<LogoApp> with SingleTickerProviderStateMixin { 12 + late Animation<double> animation; 13 + late AnimationController controller; 14 + 15 + @override 16 + void initState() { 17 + super.initState(); 18 + controller = 19 + AnimationController(duration: const Duration(seconds: 2), vsync: this); 20 + animation = Tween<double>(begin: 0, end: 300).animate(controller) 21 + ..addListener(() { 22 + setState(() { 23 + // State yang berubah di sini adalah nilai objek animasi. 24 + }); 25 + }); 26 + controller.forward(); 27 + } 28 + 12 29 @override 13 30 Widget build(BuildContext context) { 14 31 return Center( 15 32 child: Container( 16 33 margin: const EdgeInsets.symmetric(vertical: 10), 17 - height: , 18 - width: , 34 + height: animation.value, 35 + width: animation.value, 19 36 child: const FlutterLogo(), 20 37 ), 21 38 ); 22 39 } 40 + 41 + @override 42 + void dispose() { 43 + controller.dispose(); 44 + super.dispose(); 45 + } 23 46 }
Sumber app: animate1
Fungsi addListener() memanggil setState(), jadi setiap kali animasi menghasilkan angka baru, maka bingkai saat ini ditandai “kotor” dan memaksa build() untuk dipanggil lagi.
Di build(), ukuran kontainer berubah karena tinggi dan lebarnya sekarang diatur menggunakan animation.value alih-alih nilai hardcoded. Eliminasi pengontrol ketika State objek dihapus untuk mencegah terjadinya kebocoran memori. Animasi Flutter Anda kini sudah selesai dibuat!
Bonus tips Dart programming: Anda mungkin tidak familiar dengan cascade notation dari Dart—tanda dua titik di .. addListener(). Arti dari sintaksis ini adalah pemanggilan metode addListener() dengan nilai yang dikembalikan dari animate().
Contoh pemakaiannya:
animation = Tween<double>(begin: 0, end: 300).animate(controller) ..addListener(() { // ··· });
Kode ini setara dengan:
animation = Tween<double>(begin: 0, end: 300).animate(controller); animation.addListener(() { // ··· });
Menyederhanakan Animasi dengan AnimatedWidget
Poin yang akan dibahas:
- Membuat Widget bergerak dengan kelas pembantu AnimatedWidget alih-alih addListener() dan setState().
- Menggunakan AnimatedWidget untuk membuat Widget yang bisa mengulang animasi yang sama. Pakai AnimatedBuilder untuk memisahkan widget dengan transisinya.
- Contoh AnimatedWidgets dalam Flutter API: AnimatedBuilder, AnimatedModalBarrier, DecoratedBoxTransition, FadeTransition, PositionedTransition, RelativePositionedTransition, RotationTransition, ScaleTransition, SizeTransition, SlideTransition.
Kelas dasar AnimatedWidget memungkinkan Anda memisahkan kode widget inti dari kode animasinya. AnimatedWidget tidak perlu mempertahankan objek State untuk menyimpan sebuah animasi. Cukup tambahkan kelas AnimatedLogo berikut:
lib/main.dart (AnimatedLogo) class AnimatedLogo extends AnimatedWidget { const AnimatedLogo({super.key, required Animation<double> animation}) : super(listenable: animation); @override Widget build(BuildContext context) { final animation = listenable as Animation<double>; return Center( child: Container( margin: const EdgeInsets.symmetric(vertical: 10), height: animation.value, width: animation.value, child: const FlutterLogo(), ), ); } }
AnimatedLogo menggunakan nilai animasi saat ini saat menggambar dirinya sendiri.
Sedangkan LogoApp masih mengelola AnimationController dan Tween, sekaligus meneruskan objek Animation ke AnimatedLogo:
{animate1 → animate2}/lib/main.dart Viewed @@ -1,10 +1,28 @@ 1 1 import 'package:flutter/material.dart'; 2 2 void main() => runApp(const LogoApp()); 3 + class AnimatedLogo extends AnimatedWidget { 4 + const AnimatedLogo({super.key, required Animation<double> animation}) 5 + : super(listenable: animation); 6 + 7 + @override 8 + Widget build(BuildContext context) { 9 + final animation = listenable as Animation<double>; 10 + return Center( 11 + child: Container( 12 + margin: const EdgeInsets.symmetric(vertical: 10), 13 + height: animation.value, 14 + width: animation.value, 15 + child: const FlutterLogo(), 16 + ), 17 + ); 18 + } 19 + } 20 + 3 21 class LogoApp extends StatefulWidget { 4 22 const LogoApp({super.key}); 5 23 @override 6 24 State<LogoApp> createState() => _LogoAppState(); 7 25 } @@ -15,32 +33,18 @@ 15 33 @override 16 34 void initState() { 17 35 super.initState(); 18 36 controller = 19 37 AnimationController(duration: const Duration(seconds: 2), vsync: this); 20 - animation = Tween<double>(begin: 0, end: 300).animate(controller) 21 - ..addListener(() { 22 - setState(() { 23 - // State yang berubah di sini adalah nilai objek animasi. 24 - }); 25 - }); 38 + animation = Tween<double>(begin: 0, end: 300).animate(controller); 26 39 controller.forward(); 27 40 } 28 41 @override 29 - Widget build(BuildContext context) 30 - return Center( 31 - child: Container( 32 - margin: const EdgeInsets.symmetric(vertical: 10), 33 - height: animation.value, 34 - width: animation.value, 35 - child: const FlutterLogo(), 36 - ), 37 - ); 38 - } 42 + Widget build(BuildContext context) => AnimatedLogo(animation: animation); 39 43 @override 40 44 void dispose() { 41 45 controller.dispose(); 42 46 super.dispose(); 43 47 }
Meninjau Progres Animasi di Flutter
Poin yang akan dibahas:
- Gunakan addStatusListener() untuk mendapat pemberitahuan pada perubahan status animasi, seperti memulai, menghentikan, atau membalikkan arah.
- Jalankan animasi dalam loop tak terbatas dengan membalikkan arah saat animasi telah selesai atau kembali ke keadaan awal.
Bisa mengetahui kapan animasi mengubah status, seperti menyelesaikan, bergerak maju, atau berbalik posisi akan sangat membantu para animator. Anda dapat memperoleh notifikasi untuk hal-hal ini dengan mengaktifkan addStatusListener().
Contoh coding berikut memodifikasi contoh sebelumnya, sehingga kini bisa menangkap adanya perubahan status dan mencetak pembaruan. Baris yang diberi sorotan adalah bagian yang berubah:
class _LogoAppState extends State<LogoApp> with SingleTickerProviderStateMixin { late Animation<double> animation; late AnimationController controller; @override void initState() { super.initState(); controller = AnimationController(duration: const Duration(seconds: 2), vsync: this); animation = Tween<double>(begin: 0, end: 300).animate(controller) ..addStatusListener((status) => print('$status')); controller.forward(); } // ... }
Hasil outputnya:
AnimationStatus.forward AnimationStatus.completed
Lalu, gunakan addStatusListener() untuk membalikkan animasi ke bagian awal atau akhir. Cara ini akan menghasilkan efek “bernapas”:
{animate2 → animate3}/lib/main.dart Viewed @@ -35,7 +35,15 @@ 35 35 void initState() { 36 36 super.initState(); 37 37 controller = 38 38 AnimationController(duration: const Duration(seconds: 2), vsync: this); 39 - animation = Tween<double>(begin: 0, end: 300).animate(controller) 39 + animation = Tween<double>(begin: 0, end: 300).animate(controller) 40 + ..addStatusListener((status) { 41 + if (status == AnimationStatus.completed) { 42 + controller.reverse(); 43 + } else if (status == AnimationStatus.dismissed) { 44 + controller.forward(); 45 + } 46 + }) 47 + ..addStatusListener((status) => print('$status')); 40 48 controller.forward(); 41 49 }
Pemfaktoran Ulang dengan AnimatedBuilder
Poin yang akan dibahas:
- AnimatedBuilder memahami cara merender transisi.
- AnimatedBuilder tidak tahu cara merender Widget, atau mengolah objek animasi.
- Pakai AnimatedBuilder untuk mendeskripsikan animasi sebagai bagian dari metode build untuk widget lain. Namun gunakanlah AnimatedWidget untuk menentukan widget dengan animasi yang dapat digunakan berulang (resumable).
- Contoh AnimatedBuilders dalam Flutter API: BottomSheet, ExpansionTile, PopupMenu, ProgressIndicator, RefreshIndicator, Scaffold, SnackBar, TabBar, TextField.
Salah satu masalah dalam contoh kode pemrograman sebelumnya adalah kita harus ikut mengubah widget yang merender logo ketika mengganti animasi. Maka dari itu, ada baiknya untuk memisahkan sektor-sektor fungsi ke dalam kelas berbeda demi menyederhanakan kinerja:
- Render logo.
- Definisikan objek animasi.
- Render tranisis.
Pemisahan tersebut bisa diselesaikan dengan kelas AnimatedBuilder. Ia merupakan kelas terpisah dalam susunan pohon render. AnimatedWidget, AnimatedBuilder secara otomatis menangkap notifikasi dari objek animasi dan menandai struktur pohon Widget sebagai “kotor”. Alhasil Anda tidak perlu memanggil addListener() secara manual.
Dimulai dari bagian bawah pohon widget, kode untuk merender logo sangat mudah:
class LogoWidget extends StatelessWidget { const LogoWidget({super.key}); // Kosongkan bagian height dan width untuk memuat nilai induk animasi @override Widget build(BuildContext context) { return Container( margin: const EdgeInsets.symmetric(vertical: 10), child: const FlutterLogo(), ); } }
Tiga blok tengah dalam diagram semuanya dibuat dalam metode build() di GrowTransition, yang ditunjukkan di bawah ini. Widget GrowTransition sendiri bersifat stateless dan menyimpan serangkaian variabel akhir yang diperlukan untuk menentukan animasi transisi.
Fungsi build() membuat dan mengembalikan AnimatedBuilder, yang menggunakan metode (Anonymous builder) dan objek LogoWidget sebagai parameternya. Pekerjaan merender transisi sebenarnya terjadi dalam metode (Anonymous builder), yang menciptakan Container dengan ukuran yang sesuai untuk memaksa LogoWidget menyusut agar pas dengan frame.
Salah satu poin rumit dalam kode di bawah ini adalah bahwa anak animasi terlihat seperti ditentukan dua kali. Namun yang sesungguhnya terjadi adalah referensi luar dari anak yang diteruskan ke AnimatedBuilder, lalu dioper ke penutupan anonim, yang kemudian menggunakan objek itu sebagai anaknya.
Hasil bersihnya nanti akan berupa AnimatedBuilder yang terselip di antara dua widget pada pohon render. Contoh codingnya adalah sebagai berikut:
class GrowTransition extends StatelessWidget { const GrowTransition( {required this.child, required this.animation, super.key}); final Widget child; final Animation<double> animation; @override Widget build(BuildContext context) { return Center( child: AnimatedBuilder( animation: animation, builder: (context, child) { return SizedBox( height: animation.value, width: animation.value, child: child, ); }, child: child, ), ); } }
Akhirnya, kode untuk menginisialisasi animasi terlihat sangat mirip dengan contoh animate2. Metode initState() membuat AnimationController dan Tween, lalu mengikatnya dengan animate().
“Keajaiban” terjadi dalam metode build(), yang mengembalikan objek GrowTransition dengan LogoWidget sebagai anak, dan objek animasi untuk mendorong terjadinya transisi. Inilah tiga elemen yang tercantum dalam poin-poin yang telah dijabarkan sebelumnya.
{animate2 → animate4}/lib/main.dart Viewed @@ -1,27 +1,47 @@ 1 1 import 'package:flutter/material.dart'; 2 2 void main() => runApp(const LogoApp()); 3 - class extends { 4 - const ({super.key}) 5 - 3 + class LogoWidget extends StatelessWidget { 4 + const LogoWidget({super.key}); 5 + 6 + // Leave out the height and width so it fills the animating parent 7 + @override 8 + Widget build(BuildContext context) { 9 + return Container( 10 + margin: const EdgeInsets.symmetric(vertical: 10), 11 + child: const FlutterLogo(), 12 + ); 13 + } 14 + } 15 + 16 + class GrowTransition extends StatelessWidget { 17 + const GrowTransition( 18 + {required this.child, required this.animation, super.key}); 19 + 20 + final Widget child; 21 + final Animation<double> animation; 6 22 @override 7 23 Widget build(BuildContext context) { 8 - final animation = listenable as Animation<double>; 9 24 return Center( 10 - child: ( 11 - : , 12 - : , 13 - 14 - : , 25 + child: AnimatedBuilder( 26 + animation: animation, 27 + builder: (context, child) { 28 + return SizedBox( 29 + height: animation.value, 30 + width: animation.value, 31 + child: child, 32 + ); 33 + }, 34 + child: child, 15 35 ), 16 36 ); 17 37 } 18 38 } 19 39 class LogoApp extends StatefulWidget { 20 40 const LogoApp({super.key}); 21 41 @override 22 42 State<LogoApp> createState() => _LogoAppState(); @@ -34,18 +54,23 @@ 34 54 @override 35 55 void initState() { 36 56 super.initState(); 37 57 controller = 38 58 AnimationController(duration: const Duration(seconds: 2), vsync: this); 39 59 animation = Tween<double>(begin: 0, end: 300).animate(controller); 40 60 controller.forward(); 41 61 } 42 62 @override 43 - Widget build(BuildContext context) 63 + Widget build(BuildContext context) { 64 + return GrowTransition( 65 + animation: animation, 66 + child: const LogoWidget(), 67 + ); 68 + } 44 69 @override 45 70 void dispose() { 46 71 controller.dispose(); 47 72 super.dispose(); 48 73 } 49 74 }
Membuat Animasi secara Bersamaan
Poin yang akan dibahas:
- Kelas Curves mendefinisikan array kurva yang biasa digunakan, dan dapat dipakai bersamaan dengan CurvedAnimation.
Di bagian ini, Anda akan mengaplikasikan contoh pemantauan progres animasi menggunakan AnimatedWidget untuk menganimasikan efek masuk (in) dan keluar (out) secara kontinu.
Anggaplah dalam hal ini Anda ingin menganimasikan efek in dan out, dengan perubahan opasitas animasi dari transparan ke buram.
Catatan: Contoh ini menunjukkan cara menggunakan beberapa Tweens pada pengontrol animasi yang sama, di mana setiap Tweens mengelola efek yang berbeda dalam animasi. Hal ini hanya untuk tujuan ilustrasi saja. Jika Anda ingin melakukan tweening opacity dan ukuran dalam coding, sebaiknya gunakan FadeTransition dan SizeTransition.
Contoh:
controller = AnimationController(duration: const Duration(seconds: 2), vsync: this); sizeAnimation = Tween<double>(begin: 0, end: 300).animate(controller); opacityAnimation = Tween<double>(begin: 0.1, end: 1).animate(controller);
Anda bisa mendapatkan ukuran animasi dengan sizeAnimation.value dan opacity dengan opacityAnimation.value, tetapi penyusun AnimatedWidget hanya mengambil satu objek Animation saja. Untuk mengatasi masalah ini, contoh berikut menampilkan cara membuat objek Tween sendiri dan menghitung nilainya secara eksplisit.
Ubahlah AnimatedLogo untuk merangkum objek Tween-nya sendiri, dan metode build() -nya memanggil Tween.evaluate() pada objek animasi induk untuk menghitung ukuran dan nilai opacity yang diperlukan.
class AnimatedLogo extends AnimatedWidget { const AnimatedLogo({super.key, required Animation<double> animation}) : super(listenable: animation);
// Buat Tweens static karena mereka tidak berubah. static final _opacityTween = Tween<double>(begin: 0.1, end: 1); static final _sizeTween = Tween<double>(begin: 0, end: 300); @override Widget build(BuildContext context) { final animation = listenable as Animation<double>; return Center( child: Opacity( opacity: _opacityTween.evaluate(animation), child: Container( margin: const EdgeInsets.symmetric(vertical: 10), height: _sizeTween.evaluate(animation), width: _sizeTween.evaluate(animation), child: const FlutterLogo(), ), ), ); } } class LogoApp extends StatefulWidget { const LogoApp({super.key}); @override State<LogoApp> createState() => _LogoAppState(); } class _LogoAppState extends State<LogoApp> with SingleTickerProviderStateMixin { late Animation<double> animation; late AnimationController controller; @override void initState() { super.initState(); controller = AnimationController(duration: const Duration(seconds: 2), vsync: this); animation = CurvedAnimation(parent: controller, curve: Curves.easeIn) ..addStatusListener((status) { if (status == AnimationStatus.completed) { controller.reverse(); } else if (status == AnimationStatus.dismissed) { controller.forward(); } }); controller.forward(); } @override Widget build(BuildContext context) => AnimatedLogo(animation: animation); @override void dispose() { controller.dispose(); super.dispose(); } }
Demikianlah seri belajar flutter animation kali ini. Semoga tutorial coding di atas bermanfaat menambah wawasan Anda, ya!
Jangan lupa ikuti terus CODEKEY untuk dapat lebih banyak update tutorial pemrograman lainnya. Baca gratis sekarang hanya di https://codekey.id/. Sampai bertemu lagi!
Jasa Pembuatan Aplikasi, Website dan Internet Marketing | PT APPKEY
PT APPKEY adalah perusahaan IT yang khusus membuat aplikasi Android, iOS dan mengembangkan sistem website. Kami juga memiliki pengetahuan dan wawasan dalam menjalankan pemasaran online sehingga diharapkan dapat membantu menyelesaikan permasalahan Anda.