Flutter ile Tema Oluşturmak

Helmsys

Yazılım Ekibi Kıdemli
16 Mar 2022
1,492
1,651
Uzun bir sürenin ardından merhaba. Yanda sitelerin hacklendiği, burada ise çiçek böceklerin uçuştuğu dart dilinde yazılan java ile bağı olan kotlinle arkadaş Flutter frameworkü ile berabersiniz. Bu konumda çok fazla detaya inip teknik bilgi vermek yerine neyi nerede ne için kullanmışım ve bu ne işe yarıyor formatında götürmeyi planlıyorum.

Bilindiği üzere Flutter framework'ü bizler için tek bir programlama dilinde birçok iş yapabilmemize olanak tanıyor. Ama bizde herkes gibi bu iş olarak tanımladığımız kısmın yalnızca mobil tarafını görücez. Yoksa msvc derleyicisini de yükleyip masaüstü uygulama mı yapalım? Kesinlikle hayır :)

Yapacağımız uygulama tek başına "uygulama" olarak sayılacak türden değil çünkü kendi haline hiçbir iş yapacak düzeyde değil. Bu halihazırda bir projeniz varsa eklemeyi düşüneceğiniz yani kullanıcı bazlı bir çeşit "bakın uygulamada böyle bir kişiselleştirme de var" dedirten bir uygulama olacak.
(uygulama sayacı = 4)

Başlamadan önce flutter framework'üne ve gereksinimlerine sahip olmalısınız. Kurulumlarını internetten bakarak halledebilirsiniz.

Kod yazma platformu olarak Visual Studio Code text editor'ü tercih edicez çünkü herkes böyle yapıyor :)
Extension sekmesine flutter yazarak intellisense ve arayüzde yardımcı elemanlar olması adına indirip kurmanızda fayda var.

Buradan sonra anlatacaklarımı projenize göre uyarlayarak gidin. Yani tek bir ağızdan yazacağım siz kendi payınıza düşeni gerekirse alacak, almayacak ya da düzenleyeceksiniz.
Öncelikle text editörde kurmuş olduğumuz flutter eklentisi sayesinde bir proje oluşturucaz. (evet bu olmadan da konsol komutu ile de oluşturulabilir ama niye böyle oluşturmayalım ki :) )
Bizler için çeşitli klasörler ve dosyalar oluşturdu. İlgileneceğimiz tek klasör şuanlık lib klasörü ve pubspec.yaml dosyası. Çünkü içerisine dart dosyalarını ekleyeceğiz diğeriyle de bir tane harici kütüphane dahil edeceğiz.
başlangıç olarak pubspec.yaml dosyasına gidiyoruz.


YAML:
dependencies:
  flutter:
    sdk: flutter
satırını bulup "flutter:" hizasında shared_preferences: ^uygun_olan_surum" uygun_olan_surum olarak belirttiğim noktaya ben ^2.2.1 numarasını yazdım. Güncel flutter sürümü kullanıyorsanız hata vermeyecektir. Eğer hata veriyorsa hata mesajına göre uygun sürümü yükleyin. Bu kütüphane bizim android/ios cihazlarımızda belirli bir dosya yoluna(bunu belirmemize gerek yok) belirlediğimiz anahtar ifadesi doğrultusunda kaydedebildiğimiz ve bu anahtarın değerini okuyup buna göre işlemler yapabildiğimiz bir kütüphane.

- Bu kütüphane olmazsa yazdıklarımız geçersiz kalır mı?
+ Hayır. Bu kütüphane bizim uygulamamızda yapacağımız işlemin kalıcı olmasını istediğimizden, kullanıcının her girişinde yeniden ayarlamasına gerek kalmasını istemediğimizden kullanıyoruz.

Şimdi tema.dart adında bir dart dosyası oluşturalım ve aşağıdaki kodu yazalım.

Kod:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:shared_preferences/shared_preferences.dart';

class TemaSinifi {
  static ValueNotifier<ThemeMode>? _themeNotifier;
  static ThemeData? returnDarkThemeData;

  static ThemeData get secilenTemayiAl => returnDarkThemeData!;
  static ThemeData get acikTemayiAl => _acikTema;
  static ValueNotifier<ThemeMode>? get themeNotifierAl => _themeNotifier;

  static final ThemeData _acikTema = ThemeData(
    brightness: Brightness.light,
    colorScheme: const ColorScheme.light(
      background: Colors.white,
      secondary: Colors.black87,
      primary: Colors.blue,
    ),
    primaryIconTheme: const IconThemeData(
      color: Colors.blueGrey,
    ),
    appBarTheme: const AppBarTheme(
      systemOverlayStyle: SystemUiOverlayStyle(
          statusBarColor: Colors.blue,
          statusBarIconBrightness: Brightness.light),
    ),
  );

  static final ThemeData _temaSec1 = ThemeData(
    brightness: Brightness.dark,
    primaryIconTheme: const IconThemeData(
      color: Colors.amberAccent,
    ),
    colorScheme: const ColorScheme.dark(
      background: Color.fromARGB(255, 18, 18, 18),
      secondary: Colors.deepOrangeAccent,
      primary: Colors.amber,
    ),
    appBarTheme: const AppBarTheme(
      systemOverlayStyle: SystemUiOverlayStyle(
          statusBarColor: Colors.amber,
          statusBarIconBrightness: Brightness.dark),
    ),
  );
  static final ThemeData _temaSec2 = ThemeData(
    brightness: Brightness.dark,
    primaryIconTheme: const IconThemeData(
      color: Colors.purpleAccent,
    ),
    colorScheme: const ColorScheme.dark(
      background: Color.fromARGB(255, 18, 18, 18),
      secondary: Colors.purpleAccent,
      primary: Colors.deepPurple,
    ),
    appBarTheme: const AppBarTheme(
      systemOverlayStyle: SystemUiOverlayStyle(
          statusBarColor: Colors.deepPurple,
          statusBarIconBrightness: Brightness.dark),
    ),
  );

  static final ThemeData _temaSec3 = ThemeData(
    brightness: Brightness.dark,
    primaryIconTheme: const IconThemeData(
      color: Colors.blueAccent,
    ),
    colorScheme: const ColorScheme.dark(
      background: Color.fromARGB(255, 18, 18, 18),
      secondary: Colors.lightBlueAccent,
      primary: Colors.indigo,
    ),
    appBarTheme: const AppBarTheme(
      systemOverlayStyle: SystemUiOverlayStyle(
          statusBarColor: Colors.indigo,
          statusBarIconBrightness: Brightness.dark),
    ),
  );

  static Future<void> darkThemeState() async {
    SharedPreferences preferences = await SharedPreferences.getInstance();
    if (preferences.getBool('temaSecildiMi') == null) {
      _themeNotifier = ValueNotifier(ThemeMode.system);
      preferences.setBool('temaSecildiMi', false);
    }
    if (!preferences.getBool('temaSecildiMi')!) {
      _themeNotifier = ValueNotifier(ThemeMode.light);
    } else {
      _themeNotifier = ValueNotifier(ThemeMode.dark);
    }
  }

  static Future<void> saveDarkTheme(bool state) async {
    SharedPreferences preferences = await SharedPreferences.getInstance();
    await preferences.setBool('temaSecildiMi', state);
    await selectDarkTheme();
  }

  static Future<void> selectDarkTheme() async {
    SharedPreferences preferences = await SharedPreferences.getInstance();
    final List<bool> getDarkThemeStates = [
      preferences.getBool("_temaSec1") ?? false,
      preferences.getBool("_temaSec2") ?? false,
      preferences.getBool("_temaSec3") ?? false
    ];
    if (getDarkThemeStates[0]) {
      returnDarkThemeData = _temaSec1;
    }
    if (getDarkThemeStates[1]) {
      returnDarkThemeData = _temaSec2;
    }
    if (getDarkThemeStates[2]) {
      returnDarkThemeData = _temaSec3;
    }
    if (!getDarkThemeStates[0] &&
        !getDarkThemeStates[1] &&
        !getDarkThemeStates[2]) {
      returnDarkThemeData = _temaSec3;
    }
    await preferences.setBool("_temaSec1", getDarkThemeStates[0]);
    await preferences.setBool("_temaSec2", getDarkThemeStates[1]);
    await preferences.setBool("_temaSec3", getDarkThemeStates[2]);
    print("_temaSec1 = ${getDarkThemeStates[0]}");
    print("_temaSec2 = ${getDarkThemeStates[1]}");
    print("_temaSec3 = ${getDarkThemeStates[2]}");
  }
}
Burada yaptığım işlem üç adet istediğim renklerde tema oluşturup bunları seçime göre kaydedip daha sonra okuyup aşağıdaki main.dart dosyasında program her açıldığında(shared_preferences sayesinde) kayıtlı olan temayı alıp arayüzde bu renkleri bize sunması. Olabildiğince açıklayıcı yazmaya çalıştığım kodda anlaşılmayan yer varsa sorabilirsiniz.

main.dart dosyasına geldikten sonra aşağıdaki kodu yazıyoruz.

Kod:
import 'package:flutter/material.dart';
import 'package:theme_changer/home.dart';
import 'package:theme_changer/tema.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await TemaSinifi.darkThemeState();
  await TemaSinifi.selectDarkTheme();
  runApp(const MainApp());
}

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

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<ThemeMode>(
      valueListenable: TemaSinifi.themeNotifierAl!,
      builder: (BuildContext context, ThemeMode currentMode, Widget? widget) {
        return MaterialApp(
          home: const HomePage(),
          darkTheme: TemaSinifi.secilenTemayiAl,
          theme: TemaSinifi.acikTemayiAl,
          themeMode: currentMode,
        );
      },
    );
  }
}

Bu kodda farklı olarak görebileceğiniz method ve sınıflar WidgetsFlutterBinding.ensureInitialized, ValueListenableBuilder ve TemaSinifi.

> WidgetsFlutterBinding.ensureInitialized() methodu bizim widget ağacımızı (normal şartlarda bakıldığında sürekli olarak sınıflara argüman verdiğimiz iç içe yazılan widget sınıfları ile yazılmış yapıya deniyor) diğer sınıfların ve diğer sınıflardan miras alınan değişkenlerin başlatılması gerektiğini burada belirliyoruz.

> ValueListenableBuilder sınıfı ise bizim belirlediğimiz türde değer tutan, değer değiştiğinde widget ağacı üzerinden işlem yapabilmemize olanak sağlayan bir sınıf. Bunu tema değişikliği için kullanıyoruz. Daha detaylı bilgi için türkçe kaynak bırakıyorum;

> TemaSinifi sınıfı ise bizim ValueListenableBuilder sınıfı ile haberleşmesine yarayacak ValueNotifier sıfından örnekler barındıran sınıfımız.

> TemaSinifi.selectDarkTheme() methodu neden en başta yazıldı diye sorarsanız bir başka method yazmak istemeyip aynı methodun içinde TemaSinifi sınıfındaki returnDarkThemeData değişkenine değer atamak için yazdım. Eğer bunu kaldırırsanız null value hatası verecektir. Dilerseniz düzenleyip ona göre bir mantık ile kullanabilirsiniz.

main.dart dosyasında görüldüğü üzere HomePage adı verilen bir sınıf mevcut. Bu sınıfı implement edelim hemen. home.dart adında dart dosyası oluşturun ve aşağıdaki gibi doldurun.


Kod:
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:theme_changer/tema.dart';

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  bool theme1 = false;
  bool theme2 = false;
  bool theme3 = false;

  @override
  void initState() {
    super.initState();
    readThemeState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Theme.of(context).colorScheme.background,
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.primary,
        title: Text("data"),
      ),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Center(
                child: Text(
              "TEMA SEÇ",
              style: TextStyle(color: Theme.of(context).colorScheme.primary),
            )),
            const SizedBox(height: 10),
            Row(
              crossAxisAlignment: CrossAxisAlignment.center,
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                Stack(
                  alignment: Alignment.center,
                  children: [
                    Visibility(
                      visible: theme1,
                      child: Container(
                        height: 35,
                        width: 35,
                        decoration: BoxDecoration(
                            border: Border.all(
                                width: 5,
                                color: Theme.of(context).colorScheme.primary),
                            borderRadius: BorderRadius.circular(10)),
                      ),
                    ),
                    InkWell(
                      onTap: () async {
                        if (theme1) {
                          theme2 = false;
                          theme3 = false;
                        } else {
                          theme1 = true;
                          theme2 = false;
                          theme3 = false;
                        }
                        await setThemeState();
                      },
                      child: Container(
                        height: 30,
                        width: 30,
                        decoration: BoxDecoration(
                            border: Border.all(width: 1),
                            borderRadius: BorderRadius.circular(10),
                            gradient: const LinearGradient(
                                stops: [0.46, 0.56],
                                begin: Alignment.centerLeft,
                                end: Alignment.centerRight,
                                colors: [Colors.amber, Colors.black87])),
                      ),
                    ),
                  ],
                ),
                Stack(
                  alignment: Alignment.center,
                  children: [
                    Visibility(
                      visible: theme2,
                      child: Container(
                        height: 35,
                        width: 35,
                        decoration: BoxDecoration(
                            border: Border.all(
                                width: 10,
                                color: Theme.of(context).colorScheme.primary),
                            borderRadius: BorderRadius.circular(10)),
                      ),
                    ),
                    InkWell(
                      onTap: () async {
                        if (theme2) {
                          theme1 = false;
                          theme3 = false;
                        } else {
                          theme1 = false;
                          theme2 = true;
                          theme3 = false;
                        }
                        await setThemeState();
                      },
                      child: Container(
                        height: 30,
                        width: 30,
                        decoration: BoxDecoration(
                            border: Border.all(width: 1),
                            borderRadius: BorderRadius.circular(10),
                            gradient: const LinearGradient(
                                stops: [0.46, 0.56],
                                begin: Alignment.centerLeft,
                                end: Alignment.centerRight,
                                colors: [Colors.deepPurple, Colors.black87])),
                      ),
                    ),
                  ],
                ),
                Stack(
                  alignment: Alignment.center,
                  children: [
                    Visibility(
                      visible: theme3,
                      child: Container(
                        height: 35,
                        width: 35,
                        decoration: BoxDecoration(
                            border: Border.all(
                                width: 5,
                                color: Theme.of(context).colorScheme.primary),
                            borderRadius: BorderRadius.circular(10)),
                      ),
                    ),
                    InkWell(
                      onTap: () async {
                        if (theme3) {
                          theme1 = false;
                          theme2 = false;
                        } else {
                          theme1 = false;
                          theme2 = false;
                          theme3 = true;
                        }
                        await setThemeState();
                      },
                      child: Container(
                        height: 30,
                        width: 30,
                        decoration: BoxDecoration(
                          border: Border.all(width: 1),
                          borderRadius: BorderRadius.circular(10),
                          gradient: const LinearGradient(
                            stops: [0.46, 0.56],
                            begin: Alignment.centerLeft,
                            end: Alignment.centerRight,
                            colors: [Colors.indigo, Colors.black87],
                          ),
                        ),
                      ),
                    ),
                  ],
                )
              ],
            )
          ],
        ),
      ),
    );
  }

  Future<void> setThemeState() async {
    TemaSinifi.themeNotifierAl!.value = ThemeMode.light;
    TemaSinifi.themeNotifierAl!.value = ThemeMode.dark;
    SharedPreferences preferences = await SharedPreferences.getInstance();
    preferences.setBool("_temaSec1", theme1);
    preferences.setBool("_temaSec2", theme2);
    preferences.setBool("_temaSec3", theme3);
    await TemaSinifi.selectDarkTheme();
    await TemaSinifi.saveDarkTheme(true);
    setState(() {});
  }

  Future<void> readThemeState() async {
    SharedPreferences preferences = await SharedPreferences.getInstance();
    theme1 = preferences.getBool("_temaSec1") ?? false;
    theme2 = preferences.getBool("_temaSec2") ?? false;
    theme3 = preferences.getBool("_temaSec3") ?? false;
    setState(() {});
  }
}

Theme.of(context).colorSheme.background yazılı olarak gördüğünüz bu değişken ThemeData sınıfını kullanarak yaptığımız değişiklikler sonucunda değerleri almamıza yarıyor. ThemeData sınıfını da TemaSinifi sınıfına giderseniz kullandığımızı ve neden colorSheme'den background'a ulaştığımızıda anlayabilirsiniz.

Burada yapılan işlem ise başta üç adet(tema adedimiz kadar) bool veri tipi tanımladık başlangıçları false çünkü başta temalar seçilmemiş olacak. initState methoduna baktığımızda da readThemeState methodu bizi karşılıyor. Bilindiği üzere initState, StatefulWidget sınıfından miras alan widgetımızı güncelleyerek yeniden çizmemize olanak sağlıyor. Her çizim bizler için maliyet olduğundan bir defalığına çalışacak method olarak initState methodunu geliştirmişler. Bunu override ederek super.initState satırı var olan methodu kullanıyor ardından overide ettiğimizden altındaki satırları işliyor, bunu bir kez yapıyor. Tekrar yapması için uygulamanın ya da o sayfanın yeniden çağrılması gerekiyor. Bizim anasayfamız HomePage sınıfı olduğundan başlangıçta temaların durumlarını okuyoruz.

readThemeState methodunda bool değişkenlerimizin değerlerini setThemeState methodunda kaydettiklerimizi okuyoruz. Okuduğumuz değerleri SharedPreferences sayesinde gerçekleştiriyoruz, getBool methodu null safety bool döndüren bir method. Bu eğer null dönerse theme1 = preferences.getBool("_temaSec1") ?? false yazarak direk false değerini atıyoruz. İşlemler sonrası setState methodunu çağırarak widgetı yeniliyoruz.


Her işlem doğru yapıldığında bizi böyle bir son karşılıyor:
Diğer konularda görüşmek üzere.
 
Son düzenleme:

Zwo

Katılımcı Üye
Uzun bir sürenin ardından merhaba. Yanda sitelerin hacklendiği, burada ise çiçek böceklerin uçuştuğu dart dilinde yazılan java ile bağı olan kotlinle arkadaş Flutter frameworkü ile berabersiniz. Bu konumda çok fazla detaya inip teknik bilgi vermek yerine neyi nerede ne için kullanmışım ve bu ne işe yarıyor formatında götürmeyi planlıyorum.

Bilindiği üzere Flutter framework'ü bizler için tek bir programlama dilinde birçok iş yapabilmemize olanak tanıyor. Ama bizde herkes gibi bu iş olarak tanımladığımız kısmın yalnızca mobil tarafını görücez. Yoksa msvc derleyicisini de yükleyip masaüstü uygulama mı yapalım? Kesinlikle hayır :)

Yapacağımız uygulama tek başına "uygulama" olarak sayılacak türden değil çünkü kendi haline hiçbir iş yapacak düzeyde değil. Bu halihazırda bir projeniz varsa eklemeyi düşüneceğiniz yani kullanıcı bazlı bir çeşit "bakın uygulamada böyle bir kişiselleştirme de var" dedirten bir uygulama olacak.
(uygulama sayacı = 4)

Başlamadan önce flutter framework'üne ve gereksinimlerine sahip olmalısınız. Kurulumlarını internetten bakarak halledebilirsiniz.

Kod yazma platformu olarak Visual Studio Code text editor'ü tercih edicez çünkü herkes böyle yapıyor :)
Extension sekmesine flutter yazarak intellisense ve arayüzde yardımcı elemanlar olması adına indirip kurmanızda fayda var.

Buradan sonra anlatacaklarımı projenize göre uyarlayarak gidin. Yani tek bir ağızdan yazacağım siz kendi payınıza düşeni gerekirse alacak, almayacak ya da düzenleyeceksiniz.
Öncelikle text editörde kurmuş olduğumuz flutter eklentisi sayesinde bir proje oluşturucaz. (evet bu olmadan da konsol komutu ile de oluşturulabilir ama niye böyle oluşturmayalım ki :) )
Bizler için çeşitli klasörler ve dosyalar oluşturdu. İlgileneceğimiz tek klasör şuanlık lib klasörü ve pubspec.yaml dosyası. Çünkü içerisine dart dosyalarını ekleyeceğiz diğeriyle de bir tane harici kütüphane dahil edeceğiz.
başlangıç olarak pubspec.yaml dosyasına gidiyoruz.


YAML:
dependencies:
  flutter:
    sdk: flutter
satırını bulup "flutter:" hizasında shared_preferences: ^uygun_olan_surum" uygun_olan_surum olarak belirttiğim noktaya ben ^2.2.1 numarasını yazdım. Güncel flutter sürümü kullanıyorsanız hata vermeyecektir. Eğer hata veriyorsa hata mesajına göre uygun sürümü yükleyin. Bu kütüphane bizim android/ios cihazlarımızda belirli bir dosya yoluna(bunu belirmemize gerek yok) belirlediğimiz anahtar ifadesi doğrultusunda kaydedebildiğimiz ve bu anahtarın değerini okuyup buna göre işlemler yapabildiğimiz bir kütüphane.

- Bu kütüphane olmazsa yazdıklarımız geçersiz kalır mı?
+ Hayır. Bu kütüphane bizim uygulamamızda yapacağımız işlemin kalıcı olmasını istediğimizden, kullanıcının her girişinde yeniden ayarlamasına gerek kalmasını istemediğimizden kullanıyoruz.

Şimdi tema.dart adında bir dart dosyası oluşturalım ve aşağıdaki kodu yazalım.

Kod:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:shared_preferences/shared_preferences.dart';

class TemaSinifi {
  static ValueNotifier<ThemeMode>? _themeNotifier;
  static ThemeData? returnDarkThemeData;

  static ThemeData get secilenTemayiAl => returnDarkThemeData!;
  static ThemeData get acikTemayiAl => _acikTema;
  static ValueNotifier<ThemeMode>? get themeNotifierAl => _themeNotifier;

  static final ThemeData _acikTema = ThemeData(
    brightness: Brightness.light,
    colorScheme: const ColorScheme.light(
      background: Colors.white,
      secondary: Colors.black87,
      primary: Colors.blue,
    ),
    primaryIconTheme: const IconThemeData(
      color: Colors.blueGrey,
    ),
    appBarTheme: const AppBarTheme(
      systemOverlayStyle: SystemUiOverlayStyle(
          statusBarColor: Colors.blue,
          statusBarIconBrightness: Brightness.light),
    ),
  );

  static final ThemeData _temaSec1 = ThemeData(
    brightness: Brightness.dark,
    primaryIconTheme: const IconThemeData(
      color: Colors.amberAccent,
    ),
    colorScheme: const ColorScheme.dark(
      background: Color.fromARGB(255, 18, 18, 18),
      secondary: Colors.deepOrangeAccent,
      primary: Colors.amber,
    ),
    appBarTheme: const AppBarTheme(
      systemOverlayStyle: SystemUiOverlayStyle(
          statusBarColor: Colors.amber,
          statusBarIconBrightness: Brightness.dark),
    ),
  );
  static final ThemeData _temaSec2 = ThemeData(
    brightness: Brightness.dark,
    primaryIconTheme: const IconThemeData(
      color: Colors.purpleAccent,
    ),
    colorScheme: const ColorScheme.dark(
      background: Color.fromARGB(255, 18, 18, 18),
      secondary: Colors.purpleAccent,
      primary: Colors.deepPurple,
    ),
    appBarTheme: const AppBarTheme(
      systemOverlayStyle: SystemUiOverlayStyle(
          statusBarColor: Colors.deepPurple,
          statusBarIconBrightness: Brightness.dark),
    ),
  );

  static final ThemeData _temaSec3 = ThemeData(
    brightness: Brightness.dark,
    primaryIconTheme: const IconThemeData(
      color: Colors.blueAccent,
    ),
    colorScheme: const ColorScheme.dark(
      background: Color.fromARGB(255, 18, 18, 18),
      secondary: Colors.lightBlueAccent,
      primary: Colors.indigo,
    ),
    appBarTheme: const AppBarTheme(
      systemOverlayStyle: SystemUiOverlayStyle(
          statusBarColor: Colors.indigo,
          statusBarIconBrightness: Brightness.dark),
    ),
  );

  static Future<void> darkThemeState() async {
    SharedPreferences preferences = await SharedPreferences.getInstance();
    if (preferences.getBool('temaSecildiMi') == null) {
      _themeNotifier = ValueNotifier(ThemeMode.system);
      preferences.setBool('temaSecildiMi', false);
    }
    if (!preferences.getBool('temaSecildiMi')!) {
      _themeNotifier = ValueNotifier(ThemeMode.light);
    } else {
      _themeNotifier = ValueNotifier(ThemeMode.dark);
    }
  }

  static Future<void> saveDarkTheme(bool state) async {
    SharedPreferences preferences = await SharedPreferences.getInstance();
    await preferences.setBool('temaSecildiMi', state);
    await selectDarkTheme();
  }

  static Future<void> selectDarkTheme() async {
    SharedPreferences preferences = await SharedPreferences.getInstance();
    final List<bool> getDarkThemeStates = [
      preferences.getBool("_temaSec1") ?? false,
      preferences.getBool("_temaSec2") ?? false,
      preferences.getBool("_temaSec3") ?? false
    ];
    if (getDarkThemeStates[0]) {
      returnDarkThemeData = _temaSec1;
    }
    if (getDarkThemeStates[1]) {
      returnDarkThemeData = _temaSec2;
    }
    if (getDarkThemeStates[2]) {
      returnDarkThemeData = _temaSec3;
    }
    if (!getDarkThemeStates[0] &&
        !getDarkThemeStates[1] &&
        !getDarkThemeStates[2]) {
      returnDarkThemeData = _temaSec3;
    }
    await preferences.setBool("_temaSec1", getDarkThemeStates[0]);
    await preferences.setBool("_temaSec2", getDarkThemeStates[1]);
    await preferences.setBool("_temaSec3", getDarkThemeStates[2]);
    print("_temaSec1 = ${getDarkThemeStates[0]}");
    print("_temaSec2 = ${getDarkThemeStates[1]}");
    print("_temaSec3 = ${getDarkThemeStates[2]}");
  }
}
Burada yaptığım işlem üç adet istediğim renklerde tema oluşturup bunları seçime göre kaydedip daha sonra okuyup aşağıdaki main.dart dosyasında program her açıldığında(shared_preferences sayesinde) kayıtlı olan temayı alıp arayüzde bu renkleri bize sunması. Olabildiğince açıklayıcı yazmaya çalıştığım kodda anlaşılmayan yer varsa sorabilirsiniz.

main.dart dosyasına geldikten sonra aşağıdaki kodu yazıyoruz.

Kod:
import 'package:flutter/material.dart';
import 'package:theme_changer/home.dart';
import 'package:theme_changer/tema.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await TemaSinifi.darkThemeState();
  await TemaSinifi.selectDarkTheme();
  runApp(const MainApp());
}

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

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<ThemeMode>(
      valueListenable: TemaSinifi.themeNotifierAl!,
      builder: (BuildContext context, ThemeMode currentMode, Widget? widget) {
        return MaterialApp(
          home: const HomePage(),
          darkTheme: TemaSinifi.secilenTemayiAl,
          theme: TemaSinifi.acikTemayiAl,
          themeMode: currentMode,
        );
      },
    );
  }
}

Bu kodda farklı olarak görebileceğiniz method ve sınıflar WidgetsFlutterBinding.ensureInitialized, ValueListenableBuilder ve TemaSinifi.

> WidgetsFlutterBinding.ensureInitialized() methodu bizim widget ağacımızı (normal şartlarda bakıldığında sürekli olarak sınıflara argüman verdiğimiz iç içe yazılan widget sınıfları ile yazılmış yapıya deniyor) diğer sınıfların ve diğer sınıflardan miras alınan değişkenlerin başlatılması gerektiğini burada belirliyoruz.

> ValueListenableBuilder sınıfı ise bizim belirlediğimiz türde değer tutan, değer değiştiğinde widget ağacı üzerinden işlem yapabilmemize olanak sağlayan bir sınıf. Bunu tema değişikliği için kullanıyoruz. Daha detaylı bilgi için türkçe kaynak bırakıyorum;

> TemaSinifi sınıfı ise bizim ValueListenableBuilder sınıfı ile haberleşmesine yarayacak ValueNotifier sıfından örnekler barındıran sınıfımız.

> TemaSinifi.selectDarkTheme() methodu neden en başta yazıldı diye sorarsanız bir başka method yazmak istemeyip aynı methodun içinde TemaSinifi sınıfındaki returnDarkThemeData değişkenine değer atamak için yazdım. Eğer bunu kaldırırsanız null value hatası verecektir. Dilerseniz düzenleyip ona göre bir mantık ile kullanabilirsiniz.

main.dart dosyasında görüldüğü üzere HomePage adı verilen bir sınıf mevcut. Bu sınıfı implement edelim hemen. home.dart adında dart dosyası oluşturun ve aşağıdaki gibi doldurun.


Kod:
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:theme_changer/tema.dart';

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  bool theme1 = false;
  bool theme2 = false;
  bool theme3 = false;

  @override
  void initState() {
    super.initState();
    readThemeState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Theme.of(context).colorScheme.background,
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.primary,
        title: Text("data"),
      ),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Center(
                child: Text(
              "TEMA SEÇ",
              style: TextStyle(color: Theme.of(context).colorScheme.primary),
            )),
            const SizedBox(height: 10),
            Row(
              crossAxisAlignment: CrossAxisAlignment.center,
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                Stack(
                  alignment: Alignment.center,
                  children: [
                    Visibility(
                      visible: theme1,
                      child: Container(
                        height: 35,
                        width: 35,
                        decoration: BoxDecoration(
                            border: Border.all(
                                width: 5,
                                color: Theme.of(context).colorScheme.primary),
                            borderRadius: BorderRadius.circular(10)),
                      ),
                    ),
                    InkWell(
                      onTap: () async {
                        if (theme1) {
                          theme2 = false;
                          theme3 = false;
                        } else {
                          theme1 = true;
                          theme2 = false;
                          theme3 = false;
                        }
                        await setThemeState();
                      },
                      child: Container(
                        height: 30,
                        width: 30,
                        decoration: BoxDecoration(
                            border: Border.all(width: 1),
                            borderRadius: BorderRadius.circular(10),
                            gradient: const LinearGradient(
                                stops: [0.46, 0.56],
                                begin: Alignment.centerLeft,
                                end: Alignment.centerRight,
                                colors: [Colors.amber, Colors.black87])),
                      ),
                    ),
                  ],
                ),
                Stack(
                  alignment: Alignment.center,
                  children: [
                    Visibility(
                      visible: theme2,
                      child: Container(
                        height: 35,
                        width: 35,
                        decoration: BoxDecoration(
                            border: Border.all(
                                width: 10,
                                color: Theme.of(context).colorScheme.primary),
                            borderRadius: BorderRadius.circular(10)),
                      ),
                    ),
                    InkWell(
                      onTap: () async {
                        if (theme2) {
                          theme1 = false;
                          theme3 = false;
                        } else {
                          theme1 = false;
                          theme2 = true;
                          theme3 = false;
                        }
                        await setThemeState();
                      },
                      child: Container(
                        height: 30,
                        width: 30,
                        decoration: BoxDecoration(
                            border: Border.all(width: 1),
                            borderRadius: BorderRadius.circular(10),
                            gradient: const LinearGradient(
                                stops: [0.46, 0.56],
                                begin: Alignment.centerLeft,
                                end: Alignment.centerRight,
                                colors: [Colors.deepPurple, Colors.black87])),
                      ),
                    ),
                  ],
                ),
                Stack(
                  alignment: Alignment.center,
                  children: [
                    Visibility(
                      visible: theme3,
                      child: Container(
                        height: 35,
                        width: 35,
                        decoration: BoxDecoration(
                            border: Border.all(
                                width: 5,
                                color: Theme.of(context).colorScheme.primary),
                            borderRadius: BorderRadius.circular(10)),
                      ),
                    ),
                    InkWell(
                      onTap: () async {
                        if (theme3) {
                          theme1 = false;
                          theme2 = false;
                        } else {
                          theme1 = false;
                          theme2 = false;
                          theme3 = true;
                        }
                        await setThemeState();
                      },
                      child: Container(
                        height: 30,
                        width: 30,
                        decoration: BoxDecoration(
                          border: Border.all(width: 1),
                          borderRadius: BorderRadius.circular(10),
                          gradient: const LinearGradient(
                            stops: [0.46, 0.56],
                            begin: Alignment.centerLeft,
                            end: Alignment.centerRight,
                            colors: [Colors.indigo, Colors.black87],
                          ),
                        ),
                      ),
                    ),
                  ],
                )
              ],
            )
          ],
        ),
      ),
    );
  }

  Future<void> setThemeState() async {
    TemaSinifi.themeNotifierAl!.value = ThemeMode.light;
    TemaSinifi.themeNotifierAl!.value = ThemeMode.dark;
    SharedPreferences preferences = await SharedPreferences.getInstance();
    preferences.setBool("_temaSec1", theme1);
    preferences.setBool("_temaSec2", theme2);
    preferences.setBool("_temaSec3", theme3);
    await TemaSinifi.selectDarkTheme();
    await TemaSinifi.saveDarkTheme(true);
    setState(() {});
  }

  Future<void> readThemeState() async {
    SharedPreferences preferences = await SharedPreferences.getInstance();
    theme1 = preferences.getBool("_temaSec1") ?? false;
    theme2 = preferences.getBool("_temaSec2") ?? false;
    theme3 = preferences.getBool("_temaSec3") ?? false;
    setState(() {});
  }
}

Theme.of(context).colorSheme.background yazılı olarak gördüğünüz bu değişken ThemeData sınıfını kullanarak yaptığımız değişiklikler sonucunda değerleri almamıza yarıyor. ThemeData sınıfını da TemaSinifi sınıfına giderseniz kullandığımızı ve neden colorSheme'den background'a ulaştığımızıda anlayabilirsiniz.

Burada yapılan işlem ise başta üç adet(tema adedimiz kadar) bool veri tipi tanımladık başlangıçları false çünkü başta temalar seçilmemiş olacak. initState methoduna baktığımızda da readThemeState methodu bizi karşılıyor. Bilindiği üzere initState, StatefulWidget sınıfından miras alan widgetımızı güncelleyerek yeniden çizmemize olanak sağlıyor. Her çizim bizler için maliyet olduğundan bir defalığına çalışacak method olarak initState methodunu geliştirmişler. Bunu override ederek super.initState satırı var olan methodu kullanıyor ardından overide ettiğimizden altındaki satırları işliyor, bunu bir kez yapıyor. Tekrar yapması için uygulamanın ya da o sayfanın yeniden çağrılması gerekiyor. Bizim anasayfamız HomePage sınıfı olduğundan başlangıçta temaların durumlarını okuyoruz.

readThemeState methodunda bool değişkenlerimizin değerlerini setThemeState methodunda kaydettiklerimizi okuyoruz. Okuduğumuz değerleri SharedPreferences sayesinde gerçekleştiriyoruz, getBool methodu null safety bool döndüren bir method. Bu eğer null dönerse theme1 = preferences.getBool("_temaSec1") ?? false yazarak direk false değerini atıyoruz. İşlemler sonrası setState methodunu çağırarak widgetı yeniliyoruz.


Her işlem doğru yapıldığında bizi böyle bir son karşılıyor:
Diğer konularda görüşmek üzere.
Ellerinize sağlık hocam
 

drjacob

Uzman üye
21 Ocak 2012
1,773
402
localhost
Uzun bir sürenin ardından merhaba. Yanda sitelerin hacklendiği, burada ise çiçek böceklerin uçuştuğu dart dilinde yazılan java ile bağı olan kotlinle arkadaş Flutter frameworkü ile berabersiniz. Bu konumda çok fazla detaya inip teknik bilgi vermek yerine neyi nerede ne için kullanmışım ve bu ne işe yarıyor formatında götürmeyi planlıyorum.

Bilindiği üzere Flutter framework'ü bizler için tek bir programlama dilinde birçok iş yapabilmemize olanak tanıyor. Ama bizde herkes gibi bu iş olarak tanımladığımız kısmın yalnızca mobil tarafını görücez. Yoksa msvc derleyicisini de yükleyip masaüstü uygulama mı yapalım? Kesinlikle hayır :)

Yapacağımız uygulama tek başına "uygulama" olarak sayılacak türden değil çünkü kendi haline hiçbir iş yapacak düzeyde değil. Bu halihazırda bir projeniz varsa eklemeyi düşüneceğiniz yani kullanıcı bazlı bir çeşit "bakın uygulamada böyle bir kişiselleştirme de var" dedirten bir uygulama olacak.
(uygulama sayacı = 4)

Başlamadan önce flutter framework'üne ve gereksinimlerine sahip olmalısınız. Kurulumlarını internetten bakarak halledebilirsiniz.

Kod yazma platformu olarak Visual Studio Code text editor'ü tercih edicez çünkü herkes böyle yapıyor :)
Extension sekmesine flutter yazarak intellisense ve arayüzde yardımcı elemanlar olması adına indirip kurmanızda fayda var.

Buradan sonra anlatacaklarımı projenize göre uyarlayarak gidin. Yani tek bir ağızdan yazacağım siz kendi payınıza düşeni gerekirse alacak, almayacak ya da düzenleyeceksiniz.
Öncelikle text editörde kurmuş olduğumuz flutter eklentisi sayesinde bir proje oluşturucaz. (evet bu olmadan da konsol komutu ile de oluşturulabilir ama niye böyle oluşturmayalım ki :) )
Bizler için çeşitli klasörler ve dosyalar oluşturdu. İlgileneceğimiz tek klasör şuanlık lib klasörü ve pubspec.yaml dosyası. Çünkü içerisine dart dosyalarını ekleyeceğiz diğeriyle de bir tane harici kütüphane dahil edeceğiz.
başlangıç olarak pubspec.yaml dosyasına gidiyoruz.


YAML:
dependencies:
  flutter:
    sdk: flutter
satırını bulup "flutter:" hizasında shared_preferences: ^uygun_olan_surum" uygun_olan_surum olarak belirttiğim noktaya ben ^2.2.1 numarasını yazdım. Güncel flutter sürümü kullanıyorsanız hata vermeyecektir. Eğer hata veriyorsa hata mesajına göre uygun sürümü yükleyin. Bu kütüphane bizim android/ios cihazlarımızda belirli bir dosya yoluna(bunu belirmemize gerek yok) belirlediğimiz anahtar ifadesi doğrultusunda kaydedebildiğimiz ve bu anahtarın değerini okuyup buna göre işlemler yapabildiğimiz bir kütüphane.

- Bu kütüphane olmazsa yazdıklarımız geçersiz kalır mı?
+ Hayır. Bu kütüphane bizim uygulamamızda yapacağımız işlemin kalıcı olmasını istediğimizden, kullanıcının her girişinde yeniden ayarlamasına gerek kalmasını istemediğimizden kullanıyoruz.

Şimdi tema.dart adında bir dart dosyası oluşturalım ve aşağıdaki kodu yazalım.

Kod:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:shared_preferences/shared_preferences.dart';

class TemaSinifi {
  static ValueNotifier<ThemeMode>? _themeNotifier;
  static ThemeData? returnDarkThemeData;

  static ThemeData get secilenTemayiAl => returnDarkThemeData!;
  static ThemeData get acikTemayiAl => _acikTema;
  static ValueNotifier<ThemeMode>? get themeNotifierAl => _themeNotifier;

  static final ThemeData _acikTema = ThemeData(
    brightness: Brightness.light,
    colorScheme: const ColorScheme.light(
      background: Colors.white,
      secondary: Colors.black87,
      primary: Colors.blue,
    ),
    primaryIconTheme: const IconThemeData(
      color: Colors.blueGrey,
    ),
    appBarTheme: const AppBarTheme(
      systemOverlayStyle: SystemUiOverlayStyle(
          statusBarColor: Colors.blue,
          statusBarIconBrightness: Brightness.light),
    ),
  );

  static final ThemeData _temaSec1 = ThemeData(
    brightness: Brightness.dark,
    primaryIconTheme: const IconThemeData(
      color: Colors.amberAccent,
    ),
    colorScheme: const ColorScheme.dark(
      background: Color.fromARGB(255, 18, 18, 18),
      secondary: Colors.deepOrangeAccent,
      primary: Colors.amber,
    ),
    appBarTheme: const AppBarTheme(
      systemOverlayStyle: SystemUiOverlayStyle(
          statusBarColor: Colors.amber,
          statusBarIconBrightness: Brightness.dark),
    ),
  );
  static final ThemeData _temaSec2 = ThemeData(
    brightness: Brightness.dark,
    primaryIconTheme: const IconThemeData(
      color: Colors.purpleAccent,
    ),
    colorScheme: const ColorScheme.dark(
      background: Color.fromARGB(255, 18, 18, 18),
      secondary: Colors.purpleAccent,
      primary: Colors.deepPurple,
    ),
    appBarTheme: const AppBarTheme(
      systemOverlayStyle: SystemUiOverlayStyle(
          statusBarColor: Colors.deepPurple,
          statusBarIconBrightness: Brightness.dark),
    ),
  );

  static final ThemeData _temaSec3 = ThemeData(
    brightness: Brightness.dark,
    primaryIconTheme: const IconThemeData(
      color: Colors.blueAccent,
    ),
    colorScheme: const ColorScheme.dark(
      background: Color.fromARGB(255, 18, 18, 18),
      secondary: Colors.lightBlueAccent,
      primary: Colors.indigo,
    ),
    appBarTheme: const AppBarTheme(
      systemOverlayStyle: SystemUiOverlayStyle(
          statusBarColor: Colors.indigo,
          statusBarIconBrightness: Brightness.dark),
    ),
  );

  static Future<void> darkThemeState() async {
    SharedPreferences preferences = await SharedPreferences.getInstance();
    if (preferences.getBool('temaSecildiMi') == null) {
      _themeNotifier = ValueNotifier(ThemeMode.system);
      preferences.setBool('temaSecildiMi', false);
    }
    if (!preferences.getBool('temaSecildiMi')!) {
      _themeNotifier = ValueNotifier(ThemeMode.light);
    } else {
      _themeNotifier = ValueNotifier(ThemeMode.dark);
    }
  }

  static Future<void> saveDarkTheme(bool state) async {
    SharedPreferences preferences = await SharedPreferences.getInstance();
    await preferences.setBool('temaSecildiMi', state);
    await selectDarkTheme();
  }

  static Future<void> selectDarkTheme() async {
    SharedPreferences preferences = await SharedPreferences.getInstance();
    final List<bool> getDarkThemeStates = [
      preferences.getBool("_temaSec1") ?? false,
      preferences.getBool("_temaSec2") ?? false,
      preferences.getBool("_temaSec3") ?? false
    ];
    if (getDarkThemeStates[0]) {
      returnDarkThemeData = _temaSec1;
    }
    if (getDarkThemeStates[1]) {
      returnDarkThemeData = _temaSec2;
    }
    if (getDarkThemeStates[2]) {
      returnDarkThemeData = _temaSec3;
    }
    if (!getDarkThemeStates[0] &&
        !getDarkThemeStates[1] &&
        !getDarkThemeStates[2]) {
      returnDarkThemeData = _temaSec3;
    }
    await preferences.setBool("_temaSec1", getDarkThemeStates[0]);
    await preferences.setBool("_temaSec2", getDarkThemeStates[1]);
    await preferences.setBool("_temaSec3", getDarkThemeStates[2]);
    print("_temaSec1 = ${getDarkThemeStates[0]}");
    print("_temaSec2 = ${getDarkThemeStates[1]}");
    print("_temaSec3 = ${getDarkThemeStates[2]}");
  }
}
Burada yaptığım işlem üç adet istediğim renklerde tema oluşturup bunları seçime göre kaydedip daha sonra okuyup aşağıdaki main.dart dosyasında program her açıldığında(shared_preferences sayesinde) kayıtlı olan temayı alıp arayüzde bu renkleri bize sunması. Olabildiğince açıklayıcı yazmaya çalıştığım kodda anlaşılmayan yer varsa sorabilirsiniz.

main.dart dosyasına geldikten sonra aşağıdaki kodu yazıyoruz.

Kod:
import 'package:flutter/material.dart';
import 'package:theme_changer/home.dart';
import 'package:theme_changer/tema.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await TemaSinifi.darkThemeState();
  await TemaSinifi.selectDarkTheme();
  runApp(const MainApp());
}

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

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<ThemeMode>(
      valueListenable: TemaSinifi.themeNotifierAl!,
      builder: (BuildContext context, ThemeMode currentMode, Widget? widget) {
        return MaterialApp(
          home: const HomePage(),
          darkTheme: TemaSinifi.secilenTemayiAl,
          theme: TemaSinifi.acikTemayiAl,
          themeMode: currentMode,
        );
      },
    );
  }
}

Bu kodda farklı olarak görebileceğiniz method ve sınıflar WidgetsFlutterBinding.ensureInitialized, ValueListenableBuilder ve TemaSinifi.

> WidgetsFlutterBinding.ensureInitialized() methodu bizim widget ağacımızı (normal şartlarda bakıldığında sürekli olarak sınıflara argüman verdiğimiz iç içe yazılan widget sınıfları ile yazılmış yapıya deniyor) diğer sınıfların ve diğer sınıflardan miras alınan değişkenlerin başlatılması gerektiğini burada belirliyoruz.

> ValueListenableBuilder sınıfı ise bizim belirlediğimiz türde değer tutan, değer değiştiğinde widget ağacı üzerinden işlem yapabilmemize olanak sağlayan bir sınıf. Bunu tema değişikliği için kullanıyoruz. Daha detaylı bilgi için türkçe kaynak bırakıyorum;

> TemaSinifi sınıfı ise bizim ValueListenableBuilder sınıfı ile haberleşmesine yarayacak ValueNotifier sıfından örnekler barındıran sınıfımız.

> TemaSinifi.selectDarkTheme() methodu neden en başta yazıldı diye sorarsanız bir başka method yazmak istemeyip aynı methodun içinde TemaSinifi sınıfındaki returnDarkThemeData değişkenine değer atamak için yazdım. Eğer bunu kaldırırsanız null value hatası verecektir. Dilerseniz düzenleyip ona göre bir mantık ile kullanabilirsiniz.

main.dart dosyasında görüldüğü üzere HomePage adı verilen bir sınıf mevcut. Bu sınıfı implement edelim hemen. home.dart adında dart dosyası oluşturun ve aşağıdaki gibi doldurun.


Kod:
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:theme_changer/tema.dart';

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  bool theme1 = false;
  bool theme2 = false;
  bool theme3 = false;

  @override
  void initState() {
    super.initState();
    readThemeState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Theme.of(context).colorScheme.background,
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.primary,
        title: Text("data"),
      ),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Center(
                child: Text(
              "TEMA SEÇ",
              style: TextStyle(color: Theme.of(context).colorScheme.primary),
            )),
            const SizedBox(height: 10),
            Row(
              crossAxisAlignment: CrossAxisAlignment.center,
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                Stack(
                  alignment: Alignment.center,
                  children: [
                    Visibility(
                      visible: theme1,
                      child: Container(
                        height: 35,
                        width: 35,
                        decoration: BoxDecoration(
                            border: Border.all(
                                width: 5,
                                color: Theme.of(context).colorScheme.primary),
                            borderRadius: BorderRadius.circular(10)),
                      ),
                    ),
                    InkWell(
                      onTap: () async {
                        if (theme1) {
                          theme2 = false;
                          theme3 = false;
                        } else {
                          theme1 = true;
                          theme2 = false;
                          theme3 = false;
                        }
                        await setThemeState();
                      },
                      child: Container(
                        height: 30,
                        width: 30,
                        decoration: BoxDecoration(
                            border: Border.all(width: 1),
                            borderRadius: BorderRadius.circular(10),
                            gradient: const LinearGradient(
                                stops: [0.46, 0.56],
                                begin: Alignment.centerLeft,
                                end: Alignment.centerRight,
                                colors: [Colors.amber, Colors.black87])),
                      ),
                    ),
                  ],
                ),
                Stack(
                  alignment: Alignment.center,
                  children: [
                    Visibility(
                      visible: theme2,
                      child: Container(
                        height: 35,
                        width: 35,
                        decoration: BoxDecoration(
                            border: Border.all(
                                width: 10,
                                color: Theme.of(context).colorScheme.primary),
                            borderRadius: BorderRadius.circular(10)),
                      ),
                    ),
                    InkWell(
                      onTap: () async {
                        if (theme2) {
                          theme1 = false;
                          theme3 = false;
                        } else {
                          theme1 = false;
                          theme2 = true;
                          theme3 = false;
                        }
                        await setThemeState();
                      },
                      child: Container(
                        height: 30,
                        width: 30,
                        decoration: BoxDecoration(
                            border: Border.all(width: 1),
                            borderRadius: BorderRadius.circular(10),
                            gradient: const LinearGradient(
                                stops: [0.46, 0.56],
                                begin: Alignment.centerLeft,
                                end: Alignment.centerRight,
                                colors: [Colors.deepPurple, Colors.black87])),
                      ),
                    ),
                  ],
                ),
                Stack(
                  alignment: Alignment.center,
                  children: [
                    Visibility(
                      visible: theme3,
                      child: Container(
                        height: 35,
                        width: 35,
                        decoration: BoxDecoration(
                            border: Border.all(
                                width: 5,
                                color: Theme.of(context).colorScheme.primary),
                            borderRadius: BorderRadius.circular(10)),
                      ),
                    ),
                    InkWell(
                      onTap: () async {
                        if (theme3) {
                          theme1 = false;
                          theme2 = false;
                        } else {
                          theme1 = false;
                          theme2 = false;
                          theme3 = true;
                        }
                        await setThemeState();
                      },
                      child: Container(
                        height: 30,
                        width: 30,
                        decoration: BoxDecoration(
                          border: Border.all(width: 1),
                          borderRadius: BorderRadius.circular(10),
                          gradient: const LinearGradient(
                            stops: [0.46, 0.56],
                            begin: Alignment.centerLeft,
                            end: Alignment.centerRight,
                            colors: [Colors.indigo, Colors.black87],
                          ),
                        ),
                      ),
                    ),
                  ],
                )
              ],
            )
          ],
        ),
      ),
    );
  }

  Future<void> setThemeState() async {
    TemaSinifi.themeNotifierAl!.value = ThemeMode.light;
    TemaSinifi.themeNotifierAl!.value = ThemeMode.dark;
    SharedPreferences preferences = await SharedPreferences.getInstance();
    preferences.setBool("_temaSec1", theme1);
    preferences.setBool("_temaSec2", theme2);
    preferences.setBool("_temaSec3", theme3);
    await TemaSinifi.selectDarkTheme();
    await TemaSinifi.saveDarkTheme(true);
    setState(() {});
  }

  Future<void> readThemeState() async {
    SharedPreferences preferences = await SharedPreferences.getInstance();
    theme1 = preferences.getBool("_temaSec1") ?? false;
    theme2 = preferences.getBool("_temaSec2") ?? false;
    theme3 = preferences.getBool("_temaSec3") ?? false;
    setState(() {});
  }
}

Theme.of(context).colorSheme.background yazılı olarak gördüğünüz bu değişken ThemeData sınıfını kullanarak yaptığımız değişiklikler sonucunda değerleri almamıza yarıyor. ThemeData sınıfını da TemaSinifi sınıfına giderseniz kullandığımızı ve neden colorSheme'den background'a ulaştığımızıda anlayabilirsiniz.

Burada yapılan işlem ise başta üç adet(tema adedimiz kadar) bool veri tipi tanımladık başlangıçları false çünkü başta temalar seçilmemiş olacak. initState methoduna baktığımızda da readThemeState methodu bizi karşılıyor. Bilindiği üzere initState, StatefulWidget sınıfından miras alan widgetımızı güncelleyerek yeniden çizmemize olanak sağlıyor. Her çizim bizler için maliyet olduğundan bir defalığına çalışacak method olarak initState methodunu geliştirmişler. Bunu override ederek super.initState satırı var olan methodu kullanıyor ardından overide ettiğimizden altındaki satırları işliyor, bunu bir kez yapıyor. Tekrar yapması için uygulamanın ya da o sayfanın yeniden çağrılması gerekiyor. Bizim anasayfamız HomePage sınıfı olduğundan başlangıçta temaların durumlarını okuyoruz.

readThemeState methodunda bool değişkenlerimizin değerlerini setThemeState methodunda kaydettiklerimizi okuyoruz. Okuduğumuz değerleri SharedPreferences sayesinde gerçekleştiriyoruz, getBool methodu null safety bool döndüren bir method. Bu eğer null dönerse theme1 = preferences.getBool("_temaSec1") ?? false yazarak direk false değerini atıyoruz. İşlemler sonrası setState methodunu çağırarak widgetı yeniliyoruz.


Her işlem doğru yapıldığında bizi böyle bir son karşılıyor:
Diğer konularda görüşmek üzere.
eline sağlık
 
Üst

Turkhackteam.org internet sitesi 5651 sayılı kanun’un 2. maddesinin 1. fıkrasının m) bendi ile aynı kanunun 5. maddesi kapsamında "Yer Sağlayıcı" konumundadır. İçerikler ön onay olmaksızın tamamen kullanıcılar tarafından oluşturulmaktadır. Turkhackteam.org; Yer sağlayıcı olarak, kullanıcılar tarafından oluşturulan içeriği ya da hukuka aykırı paylaşımı kontrol etmekle ya da araştırmakla yükümlü değildir. Türkhackteam saldırı timleri Türk sitelerine hiçbir zararlı faaliyette bulunmaz. Türkhackteam üyelerinin yaptığı bireysel hack faaliyetlerinden Türkhackteam sorumlu değildir. Sitelerinize Türkhackteam ismi kullanılarak hack faaliyetinde bulunulursa, site-sunucu erişim loglarından bu faaliyeti gerçekleştiren ip adresini tespit edip diğer kanıtlarla birlikte savcılığa suç duyurusunda bulununuz.