↑↓ seç · Enter aç · Esc kapat

Mutlu Tekin
Mutlu Tekin
← Yazılar

Bölüm 4 — Konu 16: Theme Sistemi (ThemeData, ColorScheme)

3 dk okuma #flutter
Dizi · 16/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 Tema Sistemi Var?
  2. ThemeData — Uygulama Genelinde Stil Tanımlama
  3. Theme.of(context) — Temaya Erişim
  4. ColorScheme — Modern Renk Yönetimi
  5. Karanlık Mod (Dark Mode) Desteği
  6. Elle Tema Değiştirme — StatefulWidget ile
  7. Widget Seviyesinde Tema Geçersiz Kılma (Override)
  8. 🎯 Bu Dersten Çıkarılması Gerekenler
  9. 📝 Ödevler

Neden Tema Sistemi Var?

Şimdiye kadar, her widget'a renk/font/stil tek tek verdik (TextStyle(color: Colors.blue) gibi). Bu, küçük örnekler için sorun değil, ama gerçek bir uygulamada tutarlılığı korumak çok zorlaşır — 50 farklı ekranda "ana renk"i değiştirmek istediğinde, hepsini tek tek bulup değiştirmen gerekir. Tema sistemi, bunu merkezi bir yerden yönetmeni sağlar.

ThemeData — Uygulama Genelinde Stil Tanımlama

Bölüm 3 Konu 10'da MaterialApp'in theme: parametresini kısaca görmüştük — şimdi derinlemesine işleyelim:

dart
MaterialApp(
  theme: ThemeData(
    primaryColor: Colors.indigo,
    scaffoldBackgroundColor: Colors.grey[100],
    textTheme: TextTheme(
      headlineMedium: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
      bodyMedium: TextStyle(fontSize: 16),
    ),
    elevatedButtonTheme: ElevatedButtonThemeData(
      style: ElevatedButton.styleFrom(
        backgroundColor: Colors.indigo,
        foregroundColor: Colors.white,
      ),
    ),
  ),
  home: AnaEkran(),
)

ThemeData, Dart Bölüm 6'da öğrendiğimiz class'lar ve named parametreler kullanılarak tasarlanmış, devasa bir yapılandırma nesnesidir — düzinelerce widget türü için (butonlar, metin alanları, kartlar, vb.) varsayılan stiller tanımlamanı sağlar.

Theme.of(context) — Temaya Erişim

Bölüm 1 Konu 4'te (hot reload deneyinde) Theme.of(context).textTheme.headlineMedium kullanmıştık — şimdi bunun nasıl çalıştığını anlayalım:

dart
Text(
  'Başlık',
  style: Theme.of(context).textTheme.headlineMedium,
)

Theme.of(context) ne yapıyor? Bu, Bölüm 2 Konu 5'te "context'i şimdilik bir bilgi taşıyıcı olarak düşün" dediğimiz noktanın gerçek gücünü gösteriyor. BuildContext, widget'ın ağaçtaki konumunu bildiği için, Theme.of(context), "bu widget'ın en yakın üst ebeveyninde tanımlı olan ThemeData'yı bul" işlemini yapar. Bu, Dart Bölüm 7'de öğrendiğimiz kalıtım zincirini andıran, ama widget ağacı üzerinde çalışan bir mekanizma — "en yakın atadaki ayarı devral" mantığı.

Neden bu şekilde tasarlandı, neden global bir değişken kullanılmadı? Bölüm 8'de (Flutter müfredatı, InheritedWidget konusunda) bunun tam mekanizmasını göreceğiz — ama şimdiden bil ki, Theme.of(context)'in kendisi de bir InheritedWidget kullanır. Bu, "widget ağacı boyunca veri paylaşmanın" Flutter'daki temel yöntemidir.

ColorScheme — Modern Renk Yönetimi

Material Design 3 ile birlikte, tek tek renkler (primaryColor gibi) yerine, bütünsel bir renk sistemi olan ColorScheme öne çıktı:

dart
ThemeData(
  colorScheme: ColorScheme.fromSeed(
    seedColor: Colors.deepPurple,
  ),
)

ColorScheme.fromSeed() — bu, tek bir "tohum" (seed) renkten, Material Design'ın renk teorisi kurallarına göre, uyumlu bir renk paleti (birincil, ikincil, arka plan, hata rengi gibi düzinelerce renk) otomatik olarak üretir. Bu, elle her rengi tek tek tanımlamak yerine, tek bir karar (ana renk) ile tutarlı bir tasarım sistemi elde etmeni sağlar.

dart
Container(
  color: Theme.of(context).colorScheme.primary,
  child: Text(
    'Merhaba',
    style: TextStyle(color: Theme.of(context).colorScheme.onPrimary),
  ),
)

primary ve onPrimary ayrımı önemli: primary, ana rengi; onPrimary, o rengin üzerine yazılacak metnin rengini belirtir (genelde kontrast için beyaz/siyah). Bu isimlendirme kalıbı (on öneki), ColorScheme'in her rengi için geçerlidir (secondary/onSecondary, error/onError gibi) — Dart Bölüm 1'de öğrendiğimiz tutarlı isimlendirme prensibinin, Flutter'ın kendi API tasarımında uygulanmış hali.

Karanlık Mod (Dark Mode) Desteği

dart
MaterialApp(
  theme: ThemeData(
    colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue, brightness: Brightness.light),
  ),
  darkTheme: ThemeData(
    colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue, brightness: Brightness.dark),
  ),
  themeMode: ThemeMode.system, // sistem ayarına göre otomatik seç
  home: AnaEkran(),
)

themeMode: ThemeMode.system, Dart Bölüm 7'de öğrendiğimiz enum'a benzer bir yapı kullanır (ThemeMode, system/light/dark değerlerine sahip bir enum) — cihazın sistem ayarına (kullanıcının telefonunda karanlık mod açık mı) göre, Flutter otomatik olarak theme veya darkTheme'i seçer.

Elle Tema Değiştirme — StatefulWidget ile

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  ThemeMode _temaModu = ThemeMode.system;

  void _temaDegistir(bool karanlikMi) {
    setState(() {
      _temaModu = karanlikMi ? ThemeMode.dark : ThemeMode.light;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue)),
      darkTheme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue, brightness: Brightness.dark)),
      themeMode: _temaModu,
      home: AnaEkran(onTemaDegistir: _temaDegistir),
    );
  }
}

Bu, Bölüm 2 Konu 6'da öğrendiğimiz setState() mekanizmasını, tema bağlamında kullanıyor — _temaModu değiştiğinde, setState() tetikleniyor ve MaterialApp (ve altındaki tüm widget ağacı) yeni temaya göre yeniden çiziliyor.

Widget Seviyesinde Tema Geçersiz Kılma (Override)

dart
Theme(
  data: Theme.of(context).copyWith(
    colorScheme: Theme.of(context).colorScheme.copyWith(primary: Colors.red),
  ),
  child: ElevatedButton(
    onPressed: () {},
    child: Text('Özel Renkli Buton'),
  ),
)

Bölüm 3 Konu 12'de öğrendiğimiz copyWith() kalıbı burada tekrar karşımıza çıkıyor — var olan temayı temel alıp, sadece belirli bir kısmını değiştirerek, sadece bir widget alt ağacı için geçerli olan yerel bir tema oluşturabilirsin.


🎯 Bu Dersten Çıkarılması Gerekenler

  • ThemeData, uygulamanın genelinde tutarlı stil (renk, font, buton görünümü) tanımlamanı sağlayan merkezi bir yapılandırma nesnesidir.
  • Theme.of(context), widget ağacında "en yakın" tanımlı temayı bulur — bu, InheritedWidget mekanizmasına dayanır (Bölüm 8'de tam işleyeceğiz).
  • ColorScheme.fromSeed(), tek bir ana renkten, Material Design kurallarına uygun bütünsel bir renk paleti üretir; primary/onPrimary gibi çiftler, renk ve o rengin üzerine yazı rengini eşleştirir.
  • darkTheme + themeMode, karanlık mod desteğini sağlar; ThemeMode.system, cihaz ayarına göre otomatik seçim yapar.
  • Theme widget'ı ile, bir widget alt ağacı için yerel olarak temayı geçersiz kılabilirsin.

📝 Ödevler

  • [ ] ThemeData ile uygulamana özel bir ana renk, buton stili ve metin teması tanımla, tüm uygulamada tutarlı şekilde kullan.
  • [ ] ColorScheme.fromSeed() ile tek bir renkten tam bir renk paleti oluştur, primary/onPrimary ile bir widget stilini uygula.
  • [ ] Karanlık mod / aydınlık mod arasında geçiş yapabilen bir switch ekle (themeMode ile).
  • [ ] Theme widget'ı ve copyWith() kullanarak, sadece belirli bir widget için yerel bir tema geçersiz kılması yap.
  • [ ] Kendi cümlelerinle, "Theme.of(context) nasıl doğru temayı buluyor" sorusunu, widget ağacı ve context kavramlarıyla ilişkilendirerek açıkla (tahmin edebildiğin kadarıyla — Bölüm 8'de tam mekanizmayı göreceğiz).

Sıradaki konu: Bölüm 4 — Konu 17: Responsive & Adaptive Tasarım (MediaQuery, LayoutBuilder, OrientationBuilder, Breakpoint Stratejileri)