↑↓ seç · Enter aç · Esc kapat

Mutlu Tekin
Mutlu Tekin
← Yazılar

Bölüm 2 — Konu 9: `Expanded`, `Flexible`, `Spacer`, Intrinsic Widget'lar

4 dk okuma #flutter
Dizi · 9/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. Expanded — Kalan Alanı Doldurma
  2. flex Parametresi — Oransal Paylaşım
  3. Flexible — Expanded'in Daha Esnek Kuzeni
  4. Spacer — Boş Alan Widget'ı
  5. Intrinsic Widget'lar — IntrinsicWidth, IntrinsicHeight
  6. Hepsini Bir Arada — Pratik Bir Örnek
  7. 🎯 Bu Dersten Çıkarılması Gerekenler
  8. 📝 Ödevler
  9. 🎮 Mini Uygulama — Basit Bir "Bütçe Dağılımı" Ekranı
  10. 🏁 Bölüm 2 Tamamlandı!

Bölüm 2'nin son konusundayız. Bir önceki derste öğrendiğimiz "Row içinde sonsuz genişlik hatası" sorununu çözen araçları burada işleyeceğiz.

Expanded — Kalan Alanı Doldurma

dart
Row(
  children: [
    Container(width: 50, color: Colors.red),
    Expanded(
      child: Container(color: Colors.blue), // kalan TÜM alanı doldurur
    ),
  ],
)

Expanded, Bölüm 2 Konu 8'de öğrendiğimiz constraint sistemini "senin lehine kullanan" bir widget'tır — Row'un, çocuklarına verdiği "sonsuz genişlik" imkanını, Expanded güvenli bir şekilde çocuğuna aktarır (artık "sonsuz boyut seç" paradoksuna düşmeden, çünkü Expanded, kalan kesin alanı hesaplayıp iletir).

Nasıl çalışır — adım adım:

  1. Row, toplam genişliğini (300px diyelim) biliyor.
  2. İlk çocuk (Container(width: 50)), 50px kullanıyor.
  3. Row, kalan 250px'i, Expanded'e kesin (tight) bir kısıtlama olarak veriyor: "tam olarak 250px olmalısın."
  4. Expanded'in çocuğu (Container), bu kesin kısıtlamayı alıyor ve 250px genişliğinde çiziliyor.

flex Parametresi — Oransal Paylaşım

dart
Row(
  children: [
    Expanded(
      flex: 1,
      child: Container(color: Colors.red),
    ),
    Expanded(
      flex: 2,
      child: Container(color: Colors.blue),
    ),
  ],
)

Birden fazla Expanded kullanıldığında, kalan alan, flex değerlerinin oranına göre paylaştırılır — burada flex: 1 ve flex: 2 olduğu için, mavi kutu kırmızının iki katı genişlikte olur (toplam 3 birim, kırmızı 1/3'ü, mavi 2/3'ü alır). Varsayılan flex değeri 1'dir.

Flexible — Expanded'in Daha Esnek Kuzeni

dart
Row(
  children: [
    Flexible(
      child: Container(width: 100, color: Colors.red),
    ),
    Expanded(
      child: Container(color: Colors.blue),
    ),
  ],
)

Flexible ile Expanded arasındaki fark: Expanded, aslında Flutter'ın kaynak kodunda Flexible'dan türeyen bir sınıftır (Dart Bölüm 7'de öğrendiğimiz extends kalıtımı) — Expanded, Flexible'ın fit: FlexFit.tight (yani "kesinlikle tüm kalan alanı doldur") ile sabitlenmiş bir versiyonudur. Flexible'ın kendisi, varsayılan olarak fit: FlexFit.loose kullanır — bu, çocuğun kendi istediği kadar yer kaplamasına izin verir, ama gerekirse kalan alana kadar büyüyebilir.

dart
// Flexible (loose) — çocuk kendi boyutunu seçebilir, taşmaz
Flexible(child: Text('Kısa metin'))

// Expanded (tight) — çocuk HER ZAMAN kalan tüm alanı doldurur
Expanded(child: Text('Kısa metin')) // Text, ihtiyacından fazla yer kaplar (boş alan bırakır)

Bu, Bölüm 2 Konu 7'de Center'ın aslında Align'ın özel bir hali olduğunu öğrendiğimiz kalıba çok benzer — burada da Expanded, Flexible'ın özel (daha kısıtlayıcı) bir halidir.

Spacer — Boş Alan Widget'ı

dart
Row(
  children: [
    Text('Sol'),
    Spacer(), // aradaki tüm boşluğu doldurur
    Text('Sağ'),
  ],
)

Spacer, görünmez bir widget'tır — sadece kalan alanı doldurarak, iki widget'ı birbirinden uzaklaştırmaya yarar. Bilmen faydalı bir detay: Spacer, aslında kaynak kodda Expanded'i kullanan bir widget'tır (Expanded(child: SizedBox()) gibi bir kompozisyon) — yani Expanded'i zaten öğrendiğin için, Spacer'ın nasıl çalıştığını da örtük olarak biliyorsun. Bu, Row(children: [Text('Sol'), Spacer(), Text('Sağ')]) yazmanın, MainAxisAlignment.spaceBetween kullanmaya alternatif bir yol olduğunu gösteriyor — ikisi de benzer bir görsel sonuç verir, ama Spacer'a flex de verebilirsin, bu da ona MainAxisAlignment'ın sağlamadığı bir esneklik katar.

dart
Row(
  children: [
    Text('Sol'),
    Spacer(flex: 2), // 2 birim boşluk
    Text('Orta'),
    Spacer(flex: 1), // 1 birim boşluk
    Text('Sağ'),
  ],
)

Intrinsic Widget'lar — IntrinsicWidth, IntrinsicHeight

Bölüm 2 Konu 8'de öğrendiğimiz "constraints go down, sizes go up" kuralının istisnai bir durumunu ele alan widget'lardır. Normalde bir widget, kendi doğal (intrinsic) boyutunu bilmeden, sadece kendine verilen kısıtlamaya göre boyutlanır. Bazen, bir widget grubunun hepsinin aynı genişlikte olmasını istersin — örneğin bir Column içindeki tüm butonların, en geniş olanına göre eşit genişlikte olmasını:

dart
IntrinsicWidth(
  child: Column(
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: [
      ElevatedButton(onPressed: () {}, child: Text('Kısa')),
      ElevatedButton(onPressed: () {}, child: Text('Çok Daha Uzun Bir Buton Metni')),
    ],
  ),
)

IntrinsicWidth, önce tüm çocukların "doğal olarak istediği" genişliği hesaplar, en genişini bulur, sonra hepsine bu genişliği zorunlu kılar.

Önemli performans notu: IntrinsicWidth/IntrinsicHeight, normal layout sürecinden daha maliyetlidir — çünkü layout ağacını iki kere (önce "doğal boyutları öğrenmek için", sonra "gerçek boyutlandırma için") gezmesi gerekir. Bölüm 9'da (performans) bu tür maliyetli widget'ları ne zaman kullanmaman gerektiğini derinlemesine işleyeceğiz — şimdilik, gerçekten gerekmedikçe kullanmaktan kaçınmanı öneririm.

Hepsini Bir Arada — Pratik Bir Örnek

dart
class OranliBar extends StatelessWidget {
  const OranliBar({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 30,
      child: Row(
        children: [
          Expanded(
            flex: 3,
            child: Container(color: Colors.green), // %30 (3/10)
          ),
          Expanded(
            flex: 7,
            child: Container(color: Colors.grey[300]!), // %70 (7/10)
          ),
        ],
      ),
    );
  }
}

Bu, gerçek uygulamalarda gördüğün ilerleme çubukları (progress bar) veya oran gösterge çubuklarının temel mantığıdır — flex oranlarıyla, bir alanın yüzdesel dağılımını modelliyorsun.


🎯 Bu Dersten Çıkarılması Gerekenler

  • Expanded, Row/Column içinde kalan alanı doldurur; flex parametresiyle birden fazla Expanded arasında oransal paylaşım yapılabilir.
  • Flexible, Expanded'in daha esnek üst sınıfıdır — loose modda (varsayılan), çocuk kendi boyutunu seçebilir; Expanded, bunun tight (zorunlu, tam doldurma) versiyonudur.
  • Spacer, görünmez bir boşluk widget'ıdır; arka planda Expanded kullanır, flex ile oransal boşluk oluşturabilir.
  • IntrinsicWidth/IntrinsicHeight, bir grup widget'ı "en büyük olana göre" eşitler, ama normal layout'tan daha maliyetlidir.

📝 Ödevler

  • [ ] Row içine 3 farklı Container koy, Expanded ve farklı flex oranlarıyla (1:2:1 gibi) genişlik dağıt.
  • [ ] Flexible ile Expanded arasındaki farkı, aynı Text widget'ını ikisiyle de deneyerek (görsel farkı gözlemleyerek) göster.
  • [ ] Spacer kullanarak, bir Row içinde iki widget'ı birbirinden uzaklaştır; sonra aynı sonucu MainAxisAlignment.spaceBetween ile elde et, ikisini karşılaştır.
  • [ ] IntrinsicWidth kullanarak, farklı uzunluktaki metinlere sahip birkaç butonu eşit genişlikte yap.
  • [ ] Konu 9'daki "OranliBar" örneğine benzer, kendi flex oranlarınla bir "yüzde göstergesi" çubuğu tasarla.

🎮 Mini Uygulama — Basit Bir "Bütçe Dağılımı" Ekranı

Bölüm 2'de öğrendiğin tüm layout araçlarını (Container, Row, Column, Stack, Padding, Align, Center, Expanded, Flexible, Spacer) birleştiren bir ekran tasarla:

Gereksinimler:

  • Üstte bir başlık (Text, Padding ile boşluklu).
  • Ortada, Expanded/flex kullanan bir "bütçe çubuğu" (en az 3 farklı renkli, farklı oranlı bölüm — örneğin "Kira: %40, Yemek: %30, Eğlence: %30").
  • Çubuğun altında, her kategori için bir renk göstergesi ve isim (Row içinde küçük renkli kutular + Text, Spacer ile aralarında boşluk).
  • Tüm ekran Center ve Padding ile düzgün ortalanmış ve boşluklu olsun.

Bu projede de StatelessWidget yeterli — setState()'e gerek yok. Amaç, Bölüm 2'nin tamamını kapsayan bir layout pratiği yapmak.


🏁 Bölüm 2 Tamamlandı!

Widget'larla düşünmeyi, StatelessWidget/StatefulWidget ayrımını, temel layout widget'larını, constraint sistemini ve esnek boyutlandırma araçlarını (Expanded/Flexible/Spacer) öğrendin. Artık gerçek, düzenli arayüzler kurabiliyorsun.

Sıradaki durak Bölüm 3 — İlk Gerçek Ekranlar: MaterialApp/Scaffold/AppBar ile gerçek bir uygulama iskeleti kuracak, listeler (ListView) ve navigasyon (ekranlar arası geçiş) ile ilk çok ekranlı uygulamanı yazacaksın.