↑↓ seç · Enter aç · Esc kapat

Mutlu Tekin
Mutlu Tekin
← Yazılar

Bölüm 3 — Konu 14: Navigator 1.0 — Push/Pop, Named Routes

4 dk okuma #flutter
Dizi · 14/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. Navigator — Bir Yığın (Stack) Olarak Ekranlar
  2. Navigator.push() — Yeni Bir Ekrana Geçme
  3. Navigator.pop() — Bir Önceki Ekrana Dönme
  4. Ekranlar Arası Veri Gönderme
  5. Named Routes — Yol Tabanlı Navigasyon
  6. Anonymous vs Named Routes — Ne Zaman Hangisi?
  7. 🎯 Bu Dersten Çıkarılması Gerekenler
  8. 📝 Ödevler
  9. 🏁 Bölüm 3 Tamamlandı!

Bölüm 3'ün son konusundayız. Şimdiye kadar tek ekranlı uygulamalar yazdık — bu derste, ekranlar arası geçişi öğreneceğiz.

Flutter'da ekranlar arası gezinme, Dart Bölüm 9'da (aslında Bölüm 13'te FFI ile ilişkili olarak Pointer'ı, ama asıl burada ilişkili olan) öğrendiğimiz bir veri yapısına dayanır: yığın (stack). Bunu daha net Dart Bölüm 9 Konu 43'te Kutu<T extends Comparable> gibi generic örneklerde görmüştük ama "stack" kavramının kendisini işlememiştik — kısaca: stack, "son giren ilk çıkar" (LIFO — Last In First Out) mantığıyla çalışan bir veri yapısıdır.

Navigator, tam olarak bunu kullanır: her yeni ekrana geçtiğinde, o ekran yığının üstüne "itilir" (push); geri döndüğünde, en üstteki ekran yığından "çıkarılır" (pop).

metin
Yığın (üstten alta):
  [Detay Ekranı]   <- şu an görünen (en üstte)
  [Ana Ekran]
dart
ElevatedButton(
  onPressed: () {
    Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => DetayEkrani()),
    );
  },
  child: Text('Detaya Git'),
)

Parça parça inceleyelim:

  • context — Bölüm 2 Konu 5'te gördüğümüz BuildContext, burada Navigator'a "bu widget'ın ağaçtaki neresinde olduğunu ve hangi Navigator'a ait olduğunu" söylüyor.
  • MaterialPageRoute — yeni ekranın nasıl gösterileceğini tanımlar (Material Design'a uygun geçiş animasyonuyla).
  • builder: (context) => DetayEkrani() — Bölüm 3 Konu 11'de öğrendiğimiz builder pattern'in bir başka örneği! Bir anonim fonksiyon (Dart Bölüm 5), yeni ekranın widget'ını oluşturuyor.
dart
ElevatedButton(
  onPressed: () {
    Navigator.pop(context);
  },
  child: Text('Geri Dön'),
)

pop(), yığından en üstteki ekranı çıkarır — kullanıcı, bir önceki ekrana geri döner. Not: AppBar, varsayılan olarak bir "geri" oku otomatik olarak gösterir (eğer Navigator yığınında birden fazla ekran varsa) — bu ok, arka planda zaten Navigator.pop(context) çağırır, sen elle eklemene gerek kalmaz.

Ekranlar Arası Veri Gönderme

1. Giden ekrana veri gönderme (constructor parametreleri ile):

dart
class DetayEkrani extends StatelessWidget {
  final String urunAdi;
  const DetayEkrani({super.key, required this.urunAdi});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(urunAdi)),
      body: Center(child: Text('$urunAdi detayları')),
    );
  }
}
dart
Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => DetayEkrani(urunAdi: 'Kalem')),
);

Bu, Dart Bölüm 6'da öğrendiğimiz constructor parametreleri kavramının doğrudan bir uygulaması — yeni ekranı oluştururken, tıpkı herhangi bir class'ı oluştururken parametre verir gibi veri geçiriyorsun.

2. Geri dönerken veri alma:

dart
// Detay ekranında, geri dönerken bir değer gönderiyoruz
Navigator.pop(context, 'Seçilen Ürün: Kalem');
dart
// Ana ekranda, push()'un SONUCUNU bekliyoruz
void _detayaGit() async {
  final sonuc = await Navigator.push(
    context,
    MaterialPageRoute(builder: (context) => DetayEkrani(urunAdi: 'Kalem')),
  );
  print('Geri dönen değer: $sonuc');
}

Bu, Dart Bölüm 10'da öğrendiğimiz Future/async/await'in doğrudan bir uygulaması! Navigator.push(), aslında bir Future döndürür — bu future, kullanıcı geri dönene kadar tamamlanmaz (Dart Bölüm 10 Konu 45'te öğrendiğimiz "gelecekte bir değer" kavramını hatırla). Kullanıcı Navigator.pop(context, deger) çağırdığında, bu Future o değerle tamamlanır ve await satırı devam eder. Bu, Dart'ı derinlemesine öğrenmenin Flutter'da doğrudan işine yaradığı somut bir andır.

Named Routes — Yol Tabanlı Navigasyon

Yukarıdaki yaklaşım (MaterialPageRoute ile doğrudan widget oluşturma), "anonymous routes" olarak bilinir. Alternatif olarak, her ekrana bir isim vererek, MaterialApp düzeyinde merkezi bir "yol haritası" tanımlayabilirsin:

dart
MaterialApp(
  initialRoute: '/',
  routes: {
    '/': (context) => AnaEkran(),
    '/detay': (context) => DetayEkrani(),
    '/ayarlar': (context) => AyarlarEkrani(),
  },
)

Bu, Dart Bölüm 4'te öğrendiğimiz Map<String, WidgetBuilder> yapısıdır — anahtar, yol adı ('/detay'); değer, o yolu oluşturan bir builder fonksiyonu.

Named route'a geçiş:

dart
Navigator.pushNamed(context, '/detay');

Named route ile veri gönderme (arguments ile):

dart
Navigator.pushNamed(context, '/detay', arguments: 'Kalem');
dart
class DetayEkrani extends StatelessWidget {
  const DetayEkrani({super.key});

  @override
  Widget build(BuildContext context) {
    final urunAdi = ModalRoute.of(context)!.settings.arguments as String;
    return Scaffold(
      appBar: AppBar(title: Text(urunAdi)),
      body: Center(child: Text('$urunAdi detayları')),
    );
  }
}

Dikkat et: arguments, Object? tipinde gelir — bu yüzden as String ile cast etmen gerekiyor (Dart Bölüm 2 Konu 8'de öğrendiğimiz Object ile açık tip dönüşümü kavramını hatırla). Bu, named routes'un doğrudan constructor parametresi yaklaşımına göre daha az tip güvenli olduğu bir noktadır — bu yüzden, Bölüm 3 Konu 14'te (Flutter müfredatının ileri kısmında, Bölüm 7'de) öğreneceğimiz go_router gibi paketler, bu tip güvenliği sorununu çözen daha modern bir yaklaşım sunar.

Anonymous vs Named Routes — Ne Zaman Hangisi?

Anonymous (Navigator.push + MaterialPageRoute) Named (Navigator.pushNamed)
Tip güvenliği ✅ Yüksek (constructor parametreleri) ⚠️ Düşük (arguments, cast gerektirir)
Merkezi yol haritası ❌ Yok ✅ Var (routes: {})
Deep linking desteği ⚠️ Zayıf ✅ Daha uygun
Küçük projeler için ✅ Basit ve yeterli Gereksiz karmaşıklık olabilir

Pratik tavsiye: Küçük/orta projelerde, anonymous routes (tip güvenliği için) genelde tercih edilir. Named routes, uygulaman büyüdükçe ve URL benzeri bir yapıya (özellikle web için) ihtiyaç duyduğunda daha değerli hale gelir. Bölüm 7'de (Flutter müfredatı), go_router ile bu iki yaklaşımın en iyi yönlerini birleştiren modern bir çözümü göreceğiz.


🎯 Bu Dersten Çıkarılması Gerekenler

  • Navigator, ekranları bir stack (yığın) olarak yönetir — push ile üste eklenir, pop ile çıkarılır.
  • Navigator.push(), bir Future döndürür — Navigator.pop(context, deger) ile bu future'ı bir değerle tamamlayabilirsin (Dart'taki Future/await bilginin doğrudan uygulaması).
  • Ekranlara veri, constructor parametreleriyle (anonymous routes, tip güvenli) veya arguments ile (named routes, cast gerektirir) gönderilebilir.
  • MaterialApp'in routes: haritası, Map<String, WidgetBuilder> kullanır — merkezi bir "yol haritası" tanımlamanı sağlar.

📝 Ödevler

  • [ ] İki ekranlı bir uygulama yap: ana ekrandan "Detay" ekranına Navigator.push ile geç.
  • [ ] Detay ekranına, constructor parametresiyle bir veri (örn. bir isim) gönder, ekranda göster.
  • [ ] Detay ekranında geri dönerken, Navigator.pop(context, deger) ile bir veri döndür, ana ekranda await ile bu veriyi al ve yazdır.
  • [ ] Aynı iki ekranlı yapıyı, routes: haritası ve Navigator.pushNamed kullanarak yeniden yaz.
  • [ ] Named route ile bir arguments gönder, ModalRoute.of(context)!.settings.arguments ile al ve as ile cast et.

🏁 Bölüm 3 Tamamlandı!

Gerçek bir uygulama iskeleti kurmayı (MaterialApp/Scaffold/AppBar), listeleri (ListView.builder), kendi custom widget'larını tasarlamayı ve ekranlar arası navigasyonu öğrendin. Artık çok ekranlı, gezinebilir bir uygulama yazabiliyorsun.

Sıradaki durak Bölüm 4 — Kullanıcı Girdisi & Tema: form alanları, validasyon, tema sistemi ve responsive tasarım ile devam edeceğiz.