↑↓ seç · Enter aç · Esc kapat

Mutlu Tekin
Mutlu Tekin
← Yazılar

Bölüm 8 — Konu 39: Rive / Lottie Entegrasyonu

4 dk okuma #flutter
Dizi · 39/61 Flutter Türkçe Tutorial
  1. Bölüm 1 — Konu 1: Flutter Nedir, Mimarisi (Widget → Element → RenderObject, Skia/Impeller)
  2. Bölüm 1 — Konu 2: Ortam Kurulumu (Flutter SDK, Android Studio/VS Code, Emulator/Simulator, DevTools'a İlk Bakış)
  3. Bölüm 1 — Konu 3: İlk Proje Yapısı (`pubspec.yaml`, `lib/`, Klasör Mimarisi, `flutter create` Anatomisi)
  4. Bölüm 1 — Konu 4: Hot Reload / Hot Restart Ne Yapıyor, Neden Önemli
  5. Bölüm 2 — Konu 5: "Her Şey Widget'tır" Felsefesi, Widget Ağacı
  6. Bölüm 2 — Konu 6: StatelessWidget vs StatefulWidget + `setState()` Derinlemesine (Rebuild Mekanizması)
  7. Bölüm 2 — Konu 7: Temel Layout — Container, Row, Column, Stack, Padding, Align, Center
  8. Bölüm 2 — Konu 8: Constraint Sistemi — "Constraints Go Down, Sizes Go Up, Parent Sets Position"
  9. Bölüm 2 — Konu 9: `Expanded`, `Flexible`, `Spacer`, Intrinsic Widget'lar
  10. Bölüm 3 — Konu 10: MaterialApp/CupertinoApp, Scaffold, AppBar
  11. Bölüm 3 — Konu 11: `ListView`, `GridView`, `SingleChildScrollView` (+ Builder Pattern)
  12. Bölüm 3 — Konu 12: Text, TextStyle, Icon, Image, Asset Yönetimi
  13. Bölüm 3 — Konu 13: Custom Widget Yazma Prensipleri (Composition Over Inheritance)
  14. Bölüm 3 — Konu 14: Navigator 1.0 — Push/Pop, Named Routes
  15. Bölüm 4 — Konu 15: Form, TextField/TextFormField, GlobalKey<FormState>, Validasyon
  16. Bölüm 4 — Konu 16: Theme Sistemi (ThemeData, ColorScheme)
  17. Bölüm 4 — Konu 17: Responsive & Adaptive Tasarım (MediaQuery, LayoutBuilder, OrientationBuilder, Breakpoint Stratejileri)
  18. Bölüm 5 — Konu 18: Future/Async-Await Flutter Bağlamında, FutureBuilder
  19. Bölüm 5 — Konu 19: `Stream`, `StreamBuilder`
  20. Bölüm 5 — Konu 20: HTTP İstekleri (`http` / `dio` Paketleri)
  21. Bölüm 5 — Konu 21: JSON Serialization (Manuel → `json_serializable`/`freezed`)
  22. Bölüm 5 — Konu 22: Local Storage — `shared_preferences` → `Hive` → `sqflite`/Drift
  23. Bölüm 6 — Konu 23: InheritedWidget ve InheritedModel — "Neden setState Yetmiyor" Sorusunun Cevabı
  24. Bölüm 6 — Konu 24: Provider Paketi
  25. Bölüm 6 — Konu 25: Riverpod (Modern Yaklaşım, Provider'ın Halefi)
  26. Bölüm 6 — Konu 26: BLoC/Cubit Pattern (`flutter_bloc`)
  27. Bölüm 6 — Konu 27: GetX (Tartışmalı Ama Yaygın)
  28. Bölüm 6 — Konu 28: Karşılaştırma — Hangi Projede Hangisi?
  29. Bölüm 7 — Konu 29: Navigator 2.0 (Router, RouteInformationParser, RouterDelegate)
  30. Bölüm 7 — Konu 30: `go_router` Paketi (Pratik ve Modern Çözüm)
  31. Bölüm 7 — Konu 31: Deep Linking
  32. Bölüm 7 — Konu 32: Repository Pattern, Katmanlı Mimari (Data/Domain/Presentation)
  33. Bölüm 7 — Konu 33: Dependency Injection (`get_it`, `injectable`)
  34. Bölüm 7 — Konu 34: Clean Architecture Uyarlaması, SOLID Prensipleri
  35. Bölüm 8 — Konu 35: Implicit Animasyonlar
  36. Bölüm 8 — Konu 36: Explicit Animasyonlar (`AnimationController`, `Tween`, `Curve`)
  37. Bölüm 8 — Konu 37: Hero Animasyonları
  38. Bölüm 8 — Konu 38: `CustomPainter` / `Canvas`
  39. Bölüm 8 — Konu 39: Rive / Lottie Entegrasyonu
  40. Bölüm 9 — Konu 40: Platform Channels
  41. Bölüm 9 — Konu 41: Permission Yönetimi (`permission_handler`)
  42. Bölüm 9 — Konu 42: Kamera, Konum, Sensörler
  43. Bölüm 9 — Konu 43: Push Notification (Firebase Cloud Messaging)
  44. Bölüm 9 — Konu 44: Android/iOS Build Sistemleri
  45. Bölüm 10 — Konu 45: Test Yazımı (Unit, Widget, Integration, Golden)
  46. Bölüm 10 — Konu 46: CI/CD
  47. Bölüm 10 — Konu 47: Rebuild Optimizasyonu (`const`, `key` Kullanımı)
  48. Bölüm 10 — Konu 48: DevTools Profiling
  49. Bölüm 10 — Konu 49: Lazy Loading, Pagination, Büyük Liste Performansı
  50. Bölüm 11 — Konu 50: Firebase Ekosistemi (Auth, Firestore, Storage, Functions)
  51. Bölüm 11 — Konu 51: Supabase Alternatifi
  52. Bölüm 11 — Konu 52: GraphQL (Opsiyonel)
  53. Bölüm 11 — Konu 53: Store Yayınlama Süreci (İmzalama, Listing, Versiyonlama)
  54. Bölüm 11 — Konu 54: App Size, Obfuscation, Flavor Yönetimi
  55. Bölüm 12 — Konu 55: Flutter Web / Desktop
  56. Bölüm 12 — Konu 56: Custom `RenderObject` Yazımı
  57. Bölüm 12 — Konu 57: Engine Mimarisi Derinlemesine (Impeller vs Skia)
  58. Bölüm 12 — Konu 58: Plugin Geliştirme, pub.dev'e Paket Yayınlama
  59. Bölüm 12 — Konu 59: Monorepo Mimarisi (Melos)
  60. Bölüm 12 — Konu 60: Erişilebilirlik (Accessibility) Derinlemesine
  61. Bölüm 12 — Konu 61: Yerelleştirme (Localization / i18n)
Dizinin sayfası →
İçindekiler 9 başlık
  1. Neden Hazır Animasyon Dosyaları?
  2. Lottie — After Effects Animasyonlarını Oynatma
  3. LottieBuilder + Kontrol — Konu 36'daki AnimationController ile Birleşim
  4. Rive — Etkileşimli, Durum Tabanlı Animasyonlar
  5. Lottie mi, Rive mı?
  6. Bölüm 8'i Kapatırken — Hangi Aracı Ne Zaman Kullanırsın?
  7. 🎯 Bu Dersten Çıkarılması Gerekenler
  8. 📝 Ödevler
  9. 🎮 Mini Uygulama — Bölüm 8 Checkpoint: Animasyonlu Ürün Vitrini

Bölüm 8'in son konusuna geldik. Konu 35-38'de Flutter'ın kendi animasyon araçlarını (implicit, explicit, Hero, Canvas) öğrendik — bu son derste, tasarımcılar tarafından ayrı bir araçla üretilip Flutter'a hazır dosya olarak aktarılan animasyonları nasıl kullanacağını göreceğiz.

Neden Hazır Animasyon Dosyaları?

Konu 38'de CustomPainter ile elle bir şekil çizmenin ne kadar ayrıntılı olduğunu gördün. Şimdi düşün: bir maskot karakterin zıplayarak selam vermesi, karmaşık bir yüklenme animasyonu, ya da bir onay işaretinin çiziliyormuş gibi belirmesi gibi tasarımcı-üretimi animasyonları Canvas ile elle kodlamak günler sürer. Bunun yerine, tasarımcılar bu animasyonları özel araçlarla (Adobe After Effects, Rive Editor) hazırlar, bir dosya olarak dışa aktarır, sen de bu dosyayı Flutter'da birkaç satır kodla oynatırsın.

İki popüler format var: Lottie (After Effects animasyonlarını JSON'a çeviren, Airbnb'nin açık kaynak formatı) ve Rive (kendi editörüyle gelen, etkileşimli animasyonlara daha uygun daha yeni bir format).

Lottie — After Effects Animasyonlarını Oynatma

bash
flutter pub add lottie
dart
import 'package:lottie/lottie.dart';

Lottie.asset('assets/animasyonlar/yukleniyor.json')

Bu kadar basit — assets/ klasörüne (Bölüm 3 Konu 12'de öğrendiğimiz asset yönetimini hatırla) bir .json animasyon dosyası koyup pubspec.yaml'da tanımladıktan sonra, Lottie.asset(...), animasyonu otomatik olarak oynatmaya başlar (varsayılan olarak bir kere oynar).

dart
Lottie.asset(
  'assets/animasyonlar/yukleniyor.json',
  repeat: true,        // sürekli tekrar oynat
  animate: true,        // otomatik başlasın
  width: 200,
  height: 200,
  fit: BoxFit.contain,  // Bölüm 3 Konu 12'deki BoxFit kavramını hatırla
)

Ağdan da yükleyebilirsin:

dart
Lottie.network('https://ornek.com/animasyon.json')

Bölüm 3 Konu 12'de Image.asset ile Image.network arasındaki paralel isimlendirmeyi hatırlarsan — Lottie.asset/Lottie.network, aynı tasarım kalıbını takip ediyor.

LottieBuilder + Kontrol — Konu 36'daki AnimationController ile Birleşim

Lottie animasyonunu, Konu 36'da öğrendiğimiz AnimationController ile elle kontrol edebilirsin — örneğin bir "beğen" butonuna basıldığında animasyonu bir kere oynatmak istiyorsan:

dart
class BegenButonu extends StatefulWidget {
  const BegenButonu({super.key});

  @override
  State<BegenButonu> createState() => _BegenButonuState();
}

class _BegenButonuState extends State<BegenButonu> with SingleTickerProviderStateMixin {
  late final AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this); // duration, Lottie dosyasından otomatik alınır
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () => _controller.forward(from: 0), // baştan bir kere oynat
      child: Lottie.asset(
        'assets/animasyonlar/kalp.json',
        controller: _controller,
        onLoaded: (composition) {
          _controller.duration = composition.duration; // animasyonun gerçek süresini al
        },
      ),
    );
  }
}

Dikkat et: AnimationController'ı burada kendi duration'ını elle belirtmeden oluşturduk — onLoaded callback'i, Lottie dosyası yüklendiğinde çağrılır ve dosyanın kendi doğal süresini (composition.duration) sana verir; bunu _controller.duration'a atayarak, kontrolcünün animasyon dosyasıyla tam senkronize çalışmasını sağlıyoruz.

Rive — Etkileşimli, Durum Tabanlı Animasyonlar

bash
flutter pub add rive
dart
import 'package:rive/rive.dart';

RiveAnimation.asset('assets/animasyonlar/karakter.riv')

Rive'ın Lottie'den temel farkı: Rive dosyaları, kendi içinde bir State Machine (durum makinesi) taşıyabilir — yani animasyon, tek bir doğrusal oynatım değil, girdilere göre farklı davranan bir sistem olabilir (örneğin bir karakterin "bekleme", "yürüme", "zıplama" durumları arasında, senin kontrolünle geçiş yapması).

dart
class EtkilesimliKarakter extends StatefulWidget {
  const EtkilesimliKarakter({super.key});

  @override
  State<EtkilesimliKarakter> createState() => _EtkilesimliKarakterState();
}

class _EtkilesimliKarakterState extends State<EtkilesimliKarakter> {
  StateMachineController? _controller;
  SMIBool? _tiklandiGirdisi; // State Machine'e bağlı bir boolean girdi

  void _onRiveInit(Artboard artboard) {
    final controller = StateMachineController.fromArtboard(artboard, 'Durum Makinesi');
    if (controller != null) {
      artboard.addController(controller);
      _controller = controller;
      _tiklandiGirdisi = controller.findInput<bool>('tiklandi') as SMIBool?;
    }
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        _tiklandiGirdisi?.value = true; // Rive editöründe tanımlı animasyonu tetikle
      },
      child: RiveAnimation.asset(
        'assets/animasyonlar/karakter.riv',
        onInit: _onRiveInit,
      ),
    );
  }
}

Buradaki SMIBool (State Machine Input — Boolean), Dart Bölüm 9'da öğrendiğimiz tip sistemine bir örnek: Rive, State Machine'e bool, double, "trigger" gibi farklı girdi tipleri tanımlamana izin verir; findInput<bool>('tiklandi'), generic bir arama yapıp, Rive editöründe tasarımcının tanımladığı tiklandi adlı girdiye koddan erişim sağlıyor.

Pratik gerçek: Rive dosyalarını kendin tasarlamazsın (Rive Editor ayrı bir araçtır) — genelde bir tasarımcıdan .riv dosyasını State Machine girdi isimleriyle birlikte alırsın (örn. "bu girdinin adı tiklandi, bool tipinde") ve koddan bu isimlere göre bağlarsın.

Lottie mi, Rive mı?

Lottie Rive
Kaynak araç Adobe After Effects (Bodymovin eklentisi) Rive'ın kendi editörü
Dosya formatı .json .riv
Etkileşim/durum makinesi ❌ Yok (doğrusal oynatım) ✅ Var (State Machine)
Ekosistem/örnek bolluğu Çok yaygın, geniş hazır kütüphane (LottieFiles.com) Daha yeni, büyüyen bir topluluk
Ne zaman tercih edilir Basit, tek seferlik animasyonlar (yükleniyor, onay işareti, splash) Karaktere/duruma göre değişen, etkileşimli animasyonlar (oyun benzeri UI, maskotlar)

Bölüm 8'i Kapatırken — Hangi Aracı Ne Zaman Kullanırsın?

metin
Basit bir değer değişimi (boyut, renk, opaklık)     → Implicit animasyon (Konu 35)
İnce kontrol, birden fazla bağlı animasyon           → Explicit animasyon (Konu 36)
İki ekran arasında ortak bir görselin geçişi         → Hero (Konu 37)
Veriye dayalı özel bir şekil/grafik                  → CustomPainter (Konu 38)
Tasarımcı tarafından hazırlanmış karmaşık animasyon  → Lottie / Rive (Konu 39)

Gerçek bir uygulamada, bu beş aracın hepsini bir arada kullanman gayet normaldir — örneğin bir splash screen'de Rive, kartlar arası geçişte Hero, bir yükleme göstergesinde CustomPainter, ve butonlarda implicit animasyonlar.


🎯 Bu Dersten Çıkarılması Gerekenler

  • Lottie, After Effects kökenli .json animasyonlarını oynatır — Lottie.asset/Lottie.network, Image.asset/Image.network ile aynı tasarım kalıbını takip eder.
  • Lottie animasyonları, Konu 36'daki AnimationController ile elle kontrol edilebilir; onLoaded callback'i, dosyanın gerçek süresini vermeni sağlar.
  • Rive, .riv dosyaları ve State Machine ile, girdilere göre davranışı değişen etkileşimli animasyonlar sunar — Lottie'nin sunmadığı bir özellik.
  • Rive'da StateMachineController + findInput<T>(), koddan tasarımcının tanımladığı girdilere (bool/double/trigger) bağlanmanı sağlar.
  • Basit, tek seferlik animasyonlarda Lottie; etkileşimli/durum tabanlı animasyonlarda Rive tercih edilir.
  • Bölüm 8'de öğrendiğin beş araç (implicit, explicit, Hero, CustomPainter, Lottie/Rive), gerçek bir uygulamada genelde bir arada kullanılır.

📝 Ödevler

  • [ ] LottieFiles.com'dan ücretsiz bir animasyon (örn. bir "yükleniyor" animasyonu) indir, Lottie.asset ile bir splash screen'de göster.
  • [ ] İndirdiğin bir Lottie animasyonunu, AnimationController ile bir butona basıldığında bir kere oynatacak şekilde bağla (onLoaded ile süresini al).
  • [ ] Rive'ın örnek dosyalarından (rive.app üzerindeki topluluk dosyaları) birini indir, RiveAnimation.asset ile ekranda göster.
  • [ ] Kendi cümlelerinle, "Lottie ile Rive arasındaki temel farkın, State Machine kavramıyla nasıl ilişkili olduğunu" açıkla.

🎮 Mini Uygulama — Bölüm 8 Checkpoint: Animasyonlu Ürün Vitrini

Bölüm 8'in tamamını (implicit, explicit, Hero, CustomPainter, Lottie/Rive) bir araya getiren bir mini proje:

Gereksinimler:

  • Splash screen: Uygulama açılışında 1-2 saniye gösterilen, bir Lottie animasyonu içeren bir ekran (Future.delayed ile Bölüm 5 Konu 18'i hatırlayarak, sonra ana ekrana geç).
  • Ürün listesi: ListView.builder ile bir ürün listesi; her ürün kartı, dokunulduğunda AnimatedContainer (Konu 35) ile hafifçe büyüsün (basılı tutma efekti — GestureDetector'ın onTapDown/onTapUp ile).
  • Ürün detay geçişi: Listedeki ürün resminden detay ekranına Hero (Konu 37) ile geçiş.
  • Yüklenme göstergesi: Detay ekranında, sahte bir yükleme süresi boyunca CustomPainter (Konu 38) ile çizilmiş dairesel bir ilerleme göstergesi.
  • Bonus: "Sepete Ekle" butonuna basıldığında, AnimationController (Konu 36) ile bir "başarı" ikonu (veya bir Lottie onay animasyonu) kısaca belirip kaybolsun.

Sıradaki konu: Bölüm 9 — Konu 40: Platform Channels (Native Android/iOS Koduyla Konuşma)