↑↓ seç · Enter aç · Esc kapat

Mutlu Tekin
Mutlu Tekin
← Yazılar

Bölüm 3 — Konu 11: `ListView`, `GridView`, `SingleChildScrollView` (+ Builder Pattern)

3 dk okuma #flutter
Dizi · 11/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 10 başlık
  1. Neden Kaydırılabilir (Scrollable) Widget'lara İhtiyaç Var?
  2. SingleChildScrollView — Basit Kaydırma
  3. ListView — Kaydırılabilir Liste
  4. ListView.builder — Büyük Listeler İçin Kritik Bir Kalıp
  5. ListView.separated — Öğeler Arasına Ayırıcı Ekleme
  6. GridView — Izgara Düzeni
  7. "Builder Pattern" — Neden Bu Kadar Yaygın?
  8. Gerçek Bir Örnek — Model Listesi ile
  9. 🎯 Bu Dersten Çıkarılması Gerekenler
  10. 📝 Ödevler

Neden Kaydırılabilir (Scrollable) Widget'lara İhtiyaç Var?

Bölüm 2'de öğrendiğimiz Column, çocuklarını dikey sıralar — ama eğer içerik ekran boyutunu aşarsa, Column kaydırma (scroll) yapmaz, sadece taşar ve bir hata/uyarı gösterir (sarı-siyah çizgili bir "overflow" göstergesi). Kaydırılabilir widget'lar, bu sorunu çözer.

SingleChildScrollView — Basit Kaydırma

dart
SingleChildScrollView(
  child: Column(
    children: [
      Container(height: 200, color: Colors.red),
      Container(height: 200, color: Colors.blue),
      Container(height: 200, color: Colors.green),
    ],
  ),
)

SingleChildScrollView, tek bir çocuğu (genelde bir Column) alır ve içerik ekrandan taşarsa, kullanıcının kaydırabilmesini sağlar. Bölüm 2 Konu 5'te öğrendiğimiz child parametresini hatırlarsan — burada da tek bir çocuk alıyor, tıpkı Center/Padding gibi.

Ne zaman kullanılır? İçeriğin sabit ve az sayıda olduğu, ama ekrana her zaman sığmayabileceği durumlarda (örneğin bir form ekranı).

ListView — Kaydırılabilir Liste

dart
ListView(
  children: [
    ListTile(title: Text('Öğe 1')),
    ListTile(title: Text('Öğe 2')),
    ListTile(title: Text('Öğe 3')),
  ],
)

ListView, Column + SingleChildScrollView'in birleşimi gibi düşünülebilir — hem dikey sıralar hem otomatik olarak kaydırılabilir yapar. ListTile, liste öğeleri için hazır, standart bir düzen sunan bir widget'tır (başlık, alt başlık, ikon gibi yuvaları vardır).

ListView.builder — Büyük Listeler İçin Kritik Bir Kalıp

dart
ListView.builder(
  itemCount: 100,
  itemBuilder: (BuildContext context, int index) {
    return ListTile(
      title: Text('Öğe ${index + 1}'),
    );
  },
)

Yukarıdaki basit ListView, tüm çocukları (children: [...]) anında oluşturur — 100 öğeli bir liste için, 100 widget'ı hemen, ekranda görünmese bile oluşturmuş olursun. Bu, Dart Bölüm 13 Konu 62'de öğrendiğimiz bellek verimliliği açısından israftır.

ListView.builder, bunun yerine "lazy" (tembel) çalışır — Dart Bölüm 11 Konu 51'de öğrendiğimiz lazy evaluation kavramını hatırlarsan, burada aynı felsefe uygulanıyor: itemBuilder fonksiyonu, sadece ekranda görünmesi gereken öğeler için çağrılır. Kullanıcı aşağı kaydırdıkça, yeni öğeler için itemBuilder o an çağrılır; ekrandan çıkan öğeler ise bellekten temizlenir (Dart Bölüm 13'te öğrendiğimiz garbage collection'a aday olur).

itemBuilder parametresi — Dart bilginle çözümleme:

dart
itemBuilder: (BuildContext context, int index) {
  return ListTile(title: Text('Öğe ${index + 1}'));
}

Bu, Dart Bölüm 5'te öğrendiğimiz anonim fonksiyondur — iki parametre alıyor (context ve index), bir Widget döndürüyor. index, Dart Bölüm 4'te öğrendiğimiz liste indekslerine benzer bir mantıkla, kaçıncı öğenin oluşturulduğunu belirtir (0'dan başlar).

ListView.separated — Öğeler Arasına Ayırıcı Ekleme

dart
ListView.separated(
  itemCount: 20,
  itemBuilder: (context, index) => ListTile(title: Text('Öğe $index')),
  separatorBuilder: (context, index) => Divider(),
)

separatorBuilder, her öğe arasına (öncesine değil, sonrasına da değil, tam arasına) bir widget (genelde Divider — ince bir çizgi) ekler. Bu, itemBuilder'ın aynı lazy mantığıyla çalışır.

GridView — Izgara Düzeni

dart
GridView.builder(
  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 2, // 2 sütun
    crossAxisSpacing: 8,
    mainAxisSpacing: 8,
  ),
  itemCount: 10,
  itemBuilder: (context, index) {
    return Container(
      color: Colors.blue[100 * ((index % 8) + 1)],
      child: Center(child: Text('Öğe $index')),
    );
  },
)

GridView, ListView'e çok benzer bir mantıkla çalışır (aynı builder kalıbı) ama öğeleri ızgara (grid) düzeninde, birden fazla sütunda gösterir. SliverGridDelegateWithFixedCrossAxisCount, "sabit sayıda sütun" kullanmanı sağlar (crossAxisCount: 2 — 2 sütunlu bir ızgara).

"Builder Pattern" — Neden Bu Kadar Yaygın?

ListView.builder, GridView.builder, ve ilerleyen derslerde göreceğin birçok widget, aynı deseni (pattern) paylaşır: "kaç öğe olduğunu söyle, her öğenin nasıl görüneceğini tarif eden bir fonksiyon ver, ben gerektiğinde çağırırım." Bu, Dart Bölüm 5'te öğrendiğimiz higher-order function kavramının (fonksiyonu parametre olarak alan fonksiyon) Flutter'daki en yaygın uygulamasıdır.

Neden List<Widget> yerine bu desen tercih ediliyor?

dart
// KÖTÜ pratik (büyük listeler için) — hepsini önceden oluşturur
ListView(children: List.generate(1000, (i) => ListTile(title: Text('$i'))))

// İYİ pratik — sadece görünenler oluşturulur
ListView.builder(itemCount: 1000, itemBuilder: (context, i) => ListTile(title: Text('$i')))

Dart Bölüm 4 Konu 20'de List.generate'i öğrenmiştik — burada onu kullanmak teknik olarak çalışır, ama 1000 widget'ı anında oluşturur. ListView.builder, aynı sonucu çok daha verimli şekilde, lazy olarak sağlar. Bu, Bölüm 9'da (performans) tam olarak işleyeceğimiz bir konunun erken bir önizlemesi.

Gerçek Bir Örnek — Model Listesi ile

dart
class Urun {
  final String ad;
  final double fiyat;
  Urun(this.ad, this.fiyat);
}

class UrunListesi extends StatelessWidget {
  final List<Urun> urunler;
  const UrunListesi({super.key, required this.urunler});

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: urunler.length, // Dart Bölüm 4'te öğrendiğimiz .length
      itemBuilder: (context, index) {
        final urun = urunler[index]; // Dart'ta öğrendiğimiz indeksli erişim
        return ListTile(
          title: Text(urun.ad),
          trailing: Text('${urun.fiyat} TL'),
        );
      },
    );
  }
}

Bu, Dart Bölüm 6'da öğrendiğimiz class'lar ile Flutter'ın builder deseninin birleşimini gösteriyor — gerçek bir uygulamada, sabit sayıda öğe yerine, veri modelinden gelen (bir API'den, bir veritabanından) listeleri bu şekilde göstereceksin.


🎯 Bu Dersten Çıkarılması Gerekenler

  • SingleChildScrollView, tek bir çocuğu (genelde Column) kaydırılabilir yapar; küçük, sabit içerikler için uygundur.
  • ListView, dikey kaydırılabilir bir liste oluşturur; ListView.builder, büyük listelerde lazy (sadece görünenleri oluşturarak) çalışır — Dart'taki lazy evaluation'a benzer bir performans optimizasyonu.
  • itemBuilder, bir anonim fonksiyondur (context, index alır, widget döndürür) — "builder pattern"in temelidir.
  • GridView.builder, aynı deseni ızgara düzeninde uygular.
  • ListView.separated, öğeler arasına ayırıcı widget'lar eklemeyi sağlar.

📝 Ödevler

  • [ ] SingleChildScrollView içinde, ekranı aşan yükseklikte birkaç Container oluştur, kaydırmayı test et.
  • [ ] ListView.builder ile 50 elemanlı bir liste oluştur, her satırı ListTile ile göster.
  • [ ] ListView.separated kullanarak, öğeler arasına Divider ekle.
  • [ ] GridView.builder ile 2 sütunlu, en az 10 öğeli bir ızgara oluştur.
  • [ ] Kendi tanımladığın bir class'tan (örn. Urun) oluşan bir listeyi, ListView.builder ile gösteren bir widget yaz (Konu 11'deki UrunListesi örneğine benzer).

Sıradaki konu: Bölüm 3 — Konu 12: Text, TextStyle, Icon, Image, Asset Yönetimi