↑↓ seç · Enter aç · Esc kapat

Mutlu Tekin
Mutlu Tekin
← Yazılar

Bölüm 2 — Konu 8: Constraint Sistemi — "Constraints Go Down, Sizes Go Up, Parent Sets Position"

4 dk okuma #flutter
Dizi · 8/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. Üç Kural
  2. Kural 1: "Constraints Go Down" — Kısıtlamalar Aşağı İner
  3. Kural 2: "Sizes Go Up" — Boyutlar Yukarı Çıkar
  4. Kural 3: "Parent Sets Position" — Ebeveyn Konumu Belirler
  5. Somut Bir Örnekle Tüm Süreci İzleyelim
  6. Neden Bazen "Beklenmedik" Boyutlar Görürsün? — Yaygın Tuzak
  7. Neden "Gevşek" (Loose) ve "Sıkı" (Tight) Kısıtlama Ayrımı Önemli?
  8. Bu Bilgi Pratikte Ne İşine Yarar?
  9. 🎯 Bu Dersten Çıkarılması Gerekenler
  10. 📝 Ödevler

Bu, Flutter layout'unun en temel mantığıdır — bunu anlamadan, "neden bu widget beklediğim boyutta değil" tarzı sorularla sürekli karşılaşırsın. Flutter ekibinin kendisi bu cümleyi resmi dokümantasyonda kullanır çünkü layout sisteminin özünü üç kısa ifadede özetler.

Üç Kural

Constraints go down. Sizes go up. Parent sets position. (Kısıtlamalar aşağı iner. Boyutlar yukarı çıkar. Ebeveyn konumu belirler.)

Bunu Bölüm 1 Konu 1'de öğrendiğimiz RenderObject ağacı bağlamında düşünelim — bu üç kural, aslında RenderObject'lerin birbirleriyle nasıl "konuştuğunu" tarif ediyor.

Kural 1: "Constraints Go Down" — Kısıtlamalar Aşağı İner

Bir widget, ebeveyninden (parent) bir "kısıtlama" (constraint) alır — bu kısıtlama, "minimum ve maksimum genişlik/yükseklik" şeklinde bir aralıktır, kesin bir boyut değil.

dart
Container(
  width: 300,
  height: 200,
  child: Container(
    color: Colors.blue,
    // Bu iç Container'a boyut vermedik!
  ),
)

Dıştaki Container, içteki Container'a "en fazla 300x200 olabilirsin" kısıtlamasını iletir. İçteki Container, kendi boyutunu belirtmediği için, verilen kısıtlamanın maksimumunu kullanır — yani 300x200 olur.

Kural 2: "Sizes Go Up" — Boyutlar Yukarı Çıkar

Her widget, aldığı kısıtlama içinde kendi boyutuna karar verir ve bu boyutu ebeveynine geri bildirir.

dart
Center( // Center, çocuğuna "istediğin boyutu seçebilirsin, ben seni ortalarım" der
  child: Container(
    width: 100,
    height: 100,
    color: Colors.red,
  ),
)

Container, kendine verilen (gevşek — loose) kısıtlama içinde, kendi istediği 100x100 boyutunu seçiyor ve bunu Center'a "işte benim boyutum bu" diye bildiriyor.

Kural 3: "Parent Sets Position" — Ebeveyn Konumu Belirler

Bir widget, kendi konumunu (ekranın neresinde olacağını) belirleyemez — çocuğun boyutu belli olduktan sonra, ebeveyn, bu çocuğu nereye yerleştireceğine karar verir.

dart
Center(
  child: Container(width: 100, height: 100, color: Colors.red),
)

Container, kendi boyutunu (100x100) seçti, ama ekranın neresinde duracağına kendisi karar veremez — bunu Center widget'ı belirliyor (ortaya yerleştirerek).

Somut Bir Örnekle Tüm Süreci İzleyelim

dart
Container( // 1. Dış Container: 300x300 boyut VERİYOR (kısıtlama aşağı iner)
  width: 300,
  height: 300,
  color: Colors.grey,
  child: Center( // 2. Center: kısıtlamayı aynen aktarır ama "gevşetir" (loose yapar)
    child: Container( // 3. İç Container: kendi boyutuna karar VERİR (150x150)
      width: 150,
      height: 150,
      color: Colors.blue,
    ),
  ),
)

Akış:

  1. Dış Container, 300x300 kesin kısıtlama ile başlıyor.
  2. Bu kısıtlama, Center'a aşağı doğru aktarılıyor.
  3. Center, bu kısıtlamayı kendi çocuğuna gevşek bir şekilde iletiyor: "en fazla 300x300 olabilirsin, ama istediğin kadar küçük de olabilirsin."
  4. İç Container, kendine verilen bu esneklik içinde, kendi 150x150 boyutunu seçiyor ve bunu yukarı (Center'a) bildiriyor.
  5. Center, artık çocuğunun boyutunu (150x150) bildiği için, onu kendi alanının (300x300) ortasına yerleştiriyor.

Neden Bazen "Beklenmedik" Boyutlar Görürsün? — Yaygın Tuzak

dart
Row(
  children: [
    Container(color: Colors.red, child: Text('Merhaba')),
    Container(color: Colors.blue, child: Text('Dünya')),
  ],
)

Bu genelde beklendiği gibi çalışır — her Container, içeriğinin (Text) boyutuna göre kendi boyutunu belirler. Ama şunu denersen:

dart
Row(
  children: [
    Container(color: Colors.red, width: double.infinity), // ❌ HATA!
  ],
)

Bu hata verir! Neden? Çünkü Row'un ana ekseni (yatay), çocuklarına sınırsız genişlik kısıtlaması verir (Row, "istediğin kadar genişleyebilirsin" der) — ama sen Container'a width: double.infinity (sonsuz genişlik) vermeye çalışıyorsun. "Sonsuz kısıtlama içinde sonsuz boyut seç" paradoksal bir durum yaratır ve Flutter bunu bir hata olarak fırlatır: "BoxConstraints forces an infinite width."

Bu hatayı gördüğünde artık nedenini anlıyorsun — bu, tam olarak "constraints go down, sizes go up" prensibinin ihlal edildiği bir durum. Çözüm, genelde Expanded kullanmaktır (bir sonraki derste tam olarak işleyeceğiz).

Neden "Gevşek" (Loose) ve "Sıkı" (Tight) Kısıtlama Ayrımı Önemli?

Bölüm 1 Konu 1'de öğrendiğimiz RenderObject katmanı, aslında her widget'a iki tür kısıtlama iletebilir:

  • Tight (sıkı) kısıtlama: minimum = maksimum. "Tam olarak bu boyutta olmalısın." (width: 100, height: 100 verdiğinde oluşur)
  • Loose (gevşek) kısıtlama: minimum = 0, maksimum = belirli bir değer. "En fazla şu kadar olabilirsin, istediğin kadar küçük olabilirsin."

Center, çocuğuna her zaman gevşek bir kısıtlama iletir — bu yüzden Center içindeki bir widget, "istediği" boyutu seçebilir. Container gibi bazı widget'lar ise, kendine boyut verildiğinde, çocuğuna sıkı bir kısıtlama iletebilir.

Bu Bilgi Pratikte Ne İşine Yarar?

Bu, sadece teorik bir bilgi değil — Flutter'da "neden bu widget'ım büyümüyor/küçülmüyor" sorusuyla karşılaştığında, her zaman şu soruları sormalısın:

  1. Bu widget'a ne tür bir kısıtlama geliyor? (Ebeveyni ne tür bir kısıtlama veriyor?)
  2. Bu widget, kendi boyutuna nasıl karar veriyor? (İçeriğine göre mi, yoksa maksimum kısıtlamayı mı alıyor?)
  3. Bu boyut, ebeveyne nasıl bildiriliyor ve ebeveyn onu nereye yerleştiriyor?

Bu üç soruyu sırayla sorduğunda, hemen her layout sorununu çözümleyebilir hale gelirsin — Bölüm 2 Konu 9'da öğreneceğimiz Expanded/Flexible gibi araçlar, tam olarak bu üç kuralı senin lehine kullanmanı sağlayan araçlardır.


🎯 Bu Dersten Çıkarılması Gerekenler

  • Constraints go down: bir ebeveyn, çocuğuna minimum/maksimum genişlik-yükseklik aralığı (kısıtlama) iletir.
  • Sizes go up: her widget, aldığı kısıtlama içinde kendi boyutuna karar verir ve bunu ebeveynine bildirir.
  • Parent sets position: çocuğun boyutu belirlendikten sonra, onu nereye yerleştireceğine ebeveyn karar verir — widget kendi konumunu seçemez.
  • "Sonsuz kısıtlama içinde sonsuz boyut" gibi paradoksal durumlar (Row içinde width: double.infinity), Flutter'ın en yaygın layout hatalarından birine yol açar.
  • Loose (gevşek) ve tight (sıkı) kısıtlama ayrımı, bir widget'ın ne kadar "özgür" boyut seçebileceğini belirler.

📝 Ödevler

  • [ ] Bir Container içine boyut vermeden başka bir Container koy, dıştakinin boyutunu değiştirerek içtekinin boyutunun nasıl etkilendiğini gözlemle.
  • [ ] Center içine bir Container koy, Container'a boyut ver, Center'ın onu nasıl konumlandırdığını gözlemle.
  • [ ] Bilerek Row içinde width: double.infinity vererek hatayı tetikle, hata mesajını oku ve bu dersle ilişkilendirerek yorumla.
  • [ ] Üç seviyeli bir widget ağacı kur (dış Container → Center → iç Container), her seviyede "kısıtlama nedir, boyut nedir, konum nasıl belirleniyor" sorularını kendi cümlelerinle cevapla.
  • [ ] Kendi cümlelerinle, "neden bir widget kendi konumunu seçemiyor, sadece boyutunu seçebiliyor" sorusunu açıkla.

Sıradaki konu: Bölüm 2 — Konu 9: Expanded, Flexible, Spacer, Intrinsic Widget'lar