Posted in

GetX ile Flutter Uygulaması Geliştirmek: Tema, Dil ve Sayaç Yönetimi

Flutter dünyasında performanslı, sade ve yönetilebilir bir mimari oluşturmak istiyorsanız, GetX harika bir tercih! Bu yazıda, GetX ile nasıl temadil ve durum yönetimi yapılabileceğini içeren örnek bir projeyi adım adım inceleyeceğiz.

🏗️ Proje Genel Yapısı

Projemizde şu özellikler yer alıyor:

  • Tema (Dark/Light) değiştirme
  • Dil (TR/EN) değiştirme
  • Sayaç kontrolü (her sayfada erişilebilir)
  • Drawer menü ile dinamik sayfa yönlendirmesi
  • GetX’in reactive state yönetimi (.obs)
  • GetX’in routing ve localization desteği

Tam Kod

 import 'package:flutter/material.dart';
import 'package:get/get.dart';

void main() {
  // Controller'ları Uygulama Başında Yükle
  Get.put(AppController());
  Get.put(CounterController());

  runApp(MyApp());
}

// 🌙 Tema ve Dil Kontrolü
class AppController extends GetxController {
  var isDark = false.obs;
  var locale = const Locale('en', 'US').obs;

  void toggleTheme() {
    isDark.value = !isDark.value;
    Get.changeThemeMode(isDark.value ? ThemeMode.dark : ThemeMode.light);
  }

  void changeLang(String langCode) {
    locale.value =
    langCode == 'tr' ? const Locale('tr', 'TR') : const Locale('en', 'US');
    Get.updateLocale(locale.value);
  }
}

// 🔢 Sayaç
class CounterController extends GetxController {
  var count = 0.obs;
  void increment() => count++;
}

// 🌍 Dil Desteği
class MyTranslations extends Translations {
  @override
  Map<String, Map<String, String>> get keys => {
    'en_US': {
      'home': 'Home',
      'page': 'Page',
      'change_theme': 'Change Theme',
      'change_lang': 'Change Language',
      'back': 'Back',
      'increase': 'Increase',
    },
    'tr_TR': {
      'home': 'Ana Sayfa',
      'page': 'Sayfa',
      'change_theme': 'Temayı Değiştir',
      'change_lang': 'Dili Değiştir',
      'back': 'Geri',
      'increase': 'Arttır',
    },
  };
}

// 🚀 Uygulama
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      translations: MyTranslations(),
      locale: const Locale('en', 'US'),
      fallbackLocale: const Locale('en', 'US'),
      title: 'GetX Layout App',
      theme: ThemeData.light(),
      darkTheme: ThemeData.dark(),
      themeMode: ThemeMode.system,
      initialRoute: '/',
      getPages: [
        GetPage(name: '/', page: () => LayoutPage(child: HomePage())),
        for (int i = 1; i <= 5; i++)
          GetPage(name: '/page$i', page: () => LayoutPage(child: PageX(i))),
      ],
    );
  }
}

// 🧱 LAYOUT SAYFASI
class LayoutPage extends StatelessWidget {
  final Widget child;

  LayoutPage({required this.child});

  @override
  Widget build(BuildContext context) {
    final AppController appController = Get.find();

    return Obx(
          () => Scaffold(
        appBar: AppBar(
          title: Text('GetX Layout'),
          actions: [
            IconButton(
              icon: Icon(Icons.language),
              onPressed:
                  () => appController.changeLang(
                appController.locale.value.languageCode == 'en'
                    ? 'tr'
                    : 'en',
              ),
            ),
            IconButton(
              icon: Icon(
                appController.isDark.value ? Icons.light_mode : Icons.dark_mode,
              ),
              onPressed: appController.toggleTheme,
            ),
          ],
        ),
        drawer: Drawer(
          child: ListView(
            children: [
              DrawerHeader(child: Text('Menu', style: TextStyle(fontSize: 24))),
              ListTile(title: Text('home'.tr), onTap: () => Get.offNamed('/')),
              for (int i = 1; i <= 5; i++)
                ListTile(
                  title: Text('${'page'.tr} $i'),
                  onTap: () => Get.offNamed('/page$i'),
                ),
            ],
          ),
        ),
        body: child,
      ),
    );
  }
}

// 🏠 Ana Sayfa
class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(child: Text('home'.tr, style: TextStyle(fontSize: 32)));
  }
}

// 📄 Sayfalar
class PageX extends StatelessWidget {
  final int page;
  final CounterController counterController = Get.find();
  PageX(this.page);

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Obx(
                () => Text(
              'Sayfa $page - Sayaç: ${counterController.count.value}',
              style: TextStyle(fontSize: 24),
            ),
          ),
          const SizedBox(height: 10),
          ElevatedButton(
            onPressed: counterController.increment,
            child: Text('increase'.tr),
          ),
          const SizedBox(height: 10),
          ElevatedButton(onPressed: () => Get.back(), child: Text('back'.tr)),
        ],
      ),
    );
  }
}

İki adet controller’ımız var:

AppController

: Tema ve Dil Yönetimi

var isDark = false.obs;
var locale = const Locale('en', 'US').obs;

GetX’in .obs yapısı sayesinde değer değiştiğinde UI otomatik olarak güncellenir.

  • toggleTheme() ile temayı değiştiriyoruz.
  • changeLang() ile locale güncelleniyor ve uygulama dili değişiyor.

CounterController

Sayaç

var count = 0.obs;
void increment() => count++;

Sayfalarda sayaç butonuna bastığınızda tüm sayfalarda bu değer güncellenmiş olarak görünür. Global state yönetimi tam da budur!

🌍 Çok Dilli Destek (Localization)

MyTranslations sınıfı ile iki dil arasında geçiş sağlıyoruz:

'tr_TR': {
  'home': 'Ana Sayfa',
  'increase': 'Arttır',
  ...
},
'en_US': {
  'home': 'Home',
  'increase': 'Increase',
  ...
},

Kullanıcı, AppBar’daki 🌐 ikonuna tıklayarak anında dili değiştirebilir.

🧱 LayoutPage: Uygulama İskele Yapısı

Uygulamanın ana iskeleti olan LayoutPage her sayfanın etrafına sarmalanıyor. AppBar, Drawer ve sayfa gövdesi burada tanımlı.

child: LayoutPage(child: HomePage())

Bu yapı sayesinde hem görünüm tutarlılığı sağlanıyor hem de modüler yapı korunmuş oluyor.

📄 Dinamik Sayfalar ve Navigation

GetPage listesi ile /page1, /page2 … /page5 rotaları dinamik şekilde oluşturuluyor:

GetPage(name: '/page$i', page: () => LayoutPage(child: PageX(i)))

Drawer menüsünden bu sayfalara kolayca geçiş yapılabiliyor.

🎨 Tema Değişikliği

AppBar’da tema ikonuna tıklanarak anında ThemeMode değişiyor. Bunun için:

Get.changeThemeMode(isDark.value ? ThemeMode.dark : ThemeMode.light);

Obx() widget’ı sayesinde, değer değiştiği anda UI tekrar çiziliyor.

📱 Sayfa Örneği: PageX

Obx(() => Text('Sayfa $page - Sayaç: ${counterController.count.value}'))

Her sayfa, sayaç değerini gösterir. Butona tıkladığınızda tüm sayfalarda değer güncellenir çünkü CounterController tek bir instance olarak GetX ile paylaşılmıştır.

🔚 Sonuç

Bu örnekle birlikte GetX’in güçlü yönlerini şu şekilde özetleyebiliriz:

✅ Minimal ve sade kod

✅ Kolay state yönetimi

✅ Reactive yapı ile otomatik UI güncellenmesi

✅ Tema ve dil gibi global ayarların yönetimi

✅ Route yönetiminin basitleştirilmesi

Eğer Flutter’da “bir tık daha fazla kontrol ama çok daha az kod” diyorsanız, GetX sizin için biçilmiş kaftan. Bu örneği kendi projelerinize entegre ederek oldukça ölçeklenebilir uygulamalar geliştirebilirsiniz. 🚀

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir