Belajar Flutter - Animations & UI Polish
Episode 16 of 23

Belajar Flutter - Animations & UI Polish

Episode ini memberi jiwa pada tampilan: perbedaan implicit dan explicit animations, penggunaan AnimationController, Tween, dan AnimatedBuilder, Hero animations dan transitions untuk motion design, serta CustomPaint dan advanced UI effects untuk visual yang istimewa.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Animasi bukan hiasan — motion yang baik menjelaskan hubungan antar elemen dan membuat aplikasi terasa premium. Episode 16 memetakan dua jalur animasi di Flutter: implicit animations untuk perubahan sederhana dan explicit animations untuk kontrol penuh.

Kita membahas perbedaan keduanya, AnimationController dengan Tween dan AnimatedBuilder, Hero animations dan page transitions untuk navigasi yang mulus, serta CustomPaint untuk efek visual yang tidak tersedia di widget bawaan.

Implicit vs Explicit Animations

Implicit: Animasi dalam Sekali Deklarasi

Implicit animation seperti AnimatedContainer dan AnimatedOpacity meng-animasikan perubahan property secara otomatis. Kalian hanya menyatakan nilai akhir, framework mengurus frame-nya:

AnimatedContainer dengan animasi otomatis
AnimatedContainer(
  duration: const Duration(milliseconds: 300),
  width: _luas,
  height: _luas,
  color: _warna,
  child: const Center(child: Text('Berubah')),
)

Saat _luas atau _warna berubah, AnimatedContainer men-tween dari nilai lama ke nilai baru selama 300ms. Implicit animation cocok untuk 80 persen kebutuhan animasi — cukup dan minim kode.

Kapan Pindah ke Explicit

Pilih explicit animation saat butuh kontrol: animasi berulang, interupsi, pemicu dari gesture, atau urutan multi-langkah. Mulai dari implicit, lalu naik ke explicit hanya jika kebutuhan tidak terpenuhi.

AnimationController, Tween, dan AnimatedBuilder

AnimationController

AnimationController adalah mesin animasi — ia menghasilkan nilai 0.0 sampai 1.0 dari waktu ke waktu:

AnimationController dasar
class _FadeState extends State<FadeWidget>
    with SingleTickerProviderStateMixin {
  late final AnimationController _controller = AnimationController(
    vsync: this,
    duration: const Duration(milliseconds: 400),
  );
 
  @override
  void initState() {
    super.initState();
    _controller.forward();
  }
 
  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
 
  @override
  Widget build(BuildContext context) {
    return FadeTransition(
      opacity: _controller,
      child: const Text('Muncul'),
    );
  }
}

SingleTickerProviderStateMixin menyediakan vsync untuk sinkronisasi frame. _controller.forward() memutar animasi dari 0 ke 1. Perhatikan bahwa dispose membuang controller — aturan yang sama dari episode 15.

Tween dan AnimatedBuilder

Tween memetakan nilai 0-1 ke rentang lain — misalnya 0.0 sampai 200.0 untuk perpindahan. AnimatedBuilder me-rebuild hanya bagian yang bergantung pada animasi:

Tween dengan AnimatedBuilder
AnimatedBuilder(
  animation: _controller,
  builder: (context, child) {
    return Transform.translate(
      offset: Offset(0, 200 * _controller.value),
      child: child,
    );
  },
  child: const Text('Geser ke bawah'),
)

Transform.translate memindahkan widget berdasarkan _controller.value yang di-mapping lewat perkalian. Parameter child pada AnimatedBuilder di-build sekali dan dipakai ulang — optimasi yang mencegah rebuild child pada tiap frame.

Hero Animations dan Transitions

Hero untuk Objek yang "Terbang"

Hero menghubungkan widget di dua halaman dengan animasi terbang ketika navigasi:

Hero dengan tag yang sama di dua halaman
Hero(
  tag: 'gambar-produk',
  child: Image.network('https://example.com/produk.png'),
)

Pasang Hero(tag: 'gambar-produk') di halaman pertama dan halaman tujuan dengan tag yang identik. Saat Navigator.push berjalan, Flutter meng-animasikan widget dari posisi awal ke posisi tujuan secara mulus — salah satu efek paling berkesan di aplikasi retail.

Page Transitions

Navigasi bisa diberi animasi khusus lewat PageRouteBuilder:

Custom page transition
PageRouteBuilder(
  transitionDuration: const Duration(milliseconds: 300),
  pageBuilder: (context, animation, secondaryAnimation) =>
      const DetailScreen(),
  transitionsBuilder: (context, animation, secondaryAnimation, child) {
    final curve = CurvedAnimation(
      parent: animation,
      curve: Curves.easeInOut,
    );
    return FadeTransition(opacity: curve, child: child);
  },
)

transitionsBuilder memberi kontrol penuh atas animasi transisi. Curves.easeInOut menghaluskan gerakan — hindari linear untuk kesan yang lebih natural.

CustomPaint dan Advanced UI Effects

Menggambar Sendiri dengan CustomPainter

Ketika tidak ada widget bawaan yang cukup, CustomPaint memanggil painter:

CustomPainter lingkaran dasar
class LingkaranPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.indigo
      ..style = PaintingStyle.fill;
 
    canvas.drawCircle(
      Offset(size.width / 2, size.height / 2),
      size.width / 4,
      paint,
    );
  }
 
  @override
  bool shouldRepaint(covariant LingkaranPainter oldDelegate) => false;
}
 
CustomPaint(
  size: const Size(100, 100),
  painter: LingkaranPainter(),
)

CustomPainter.paint menerima Canvas dan menggambar langsung — drawCircle, drawPath, dan drawLine adalah primitif dasarnya. shouldRepaint mengontrol kapan painter dijalankan ulang; kembalikan false jika tidak bergantung pada state.

Efek UI Lanjutan

Kombinasi toolkit animasi dengan CustomPaint membuka banyak kemungkinan: progress ring, grafik, peta, hingga effect parallax. Untuk gerakan rumit, pertimbangkan flutter_animate dan package animasi komunitas yang matang — gunakan library bila tersedia, tulis painter hanya saat dibutuhkan.

Penutup

Inti yang harus dibawa pulang:

  • Implicit animation untuk perubahan sederhana; explicit untuk kontrol penuh.
  • AnimationController menghasilkan nilai 0-1 dengan vsync dan forward.
  • Tween memetakan nilai; AnimatedBuilder me-rebuild bagian yang bergantung.
  • Hero dengan tag sama menciptakan transisi terbang antar halaman.
  • PageRouteBuilder memberi kontrol penuh atas animasi navigasi.
  • CustomPaint dan CustomPainter menggambar efek yang tidak tersedia di widget bawaan.

Di episode 17 selanjutnya kita membahas internationalization dan accessibility — i18n dengan flutter_localizations, dukungan RTL dan locale-aware formatting, accessibility best practices dengan semantics dan focus order, serta inclusive UX dan accessibility testing. Aplikasi kalian siap melayani pengguna global dan beragam.

Belajar Flutter - Animations & UI Polish | Belajar Flutter