A Flutter App with Dark and Light Theme Mini Project with Source Code

The best way to learn is to do. Then what better way to sharpen your flutter skills making this flutter app with light and dark theme. In our day to day life we use many mobile and web applications which switch from dark to light theme so seamlessly. This feature can make the users very comfortable in using our app. And user comfort generally means a happy customer which in terms is ultimately pleasing to the developer.

For those who have wondered about adding this to their app, this is the perfect blog in which we make a flutter app with light and dark theme step by step with the help of GetX and Hive.

Flutter Change app Theme With GetX

Flutter App Change Theme With Getx. Theme Stage saved using Hive. instead of hive you can use get-storage or shared preference also. This is a flutter app with light and dark theme.

Features

  • Light/dark mode toggle
  • save theme stage
  • Custom Default font
  • Android ios and web

PlugIn Use

Please make sure you add this plugins for running this.
flutter pub install get,hive_flutter,google_fonts

Getx
GoogleFonts
Hive Flutter

Dependencies

  • After you create your flutter app using flutter create yourApp command in the terminal, go inside this yourApp directory.
  • Inside yourApp open the pubspec.yaml file.
  • pubspec.yaml:
// Dependency 1
name: flutter_theme_with_getx
version: 1.0.0+1
publish_to: none
description: Flutter App Change Theme With Getx.
environment:
  sdk: ">=2.15.1 <3.0.0"

dependencies:
  cupertino_icons: ^1.0.2
  flutter:
    sdk: flutter
  get: 4.6.1
  google_fonts: ^2.1.1 // Dependency 2
  hive_flutter: ^1.1.0 // Dependency 3

dev_dependencies:
  flutter_lints: ^1.0.0
  flutter_test:
    sdk: flutter

flutter:
  uses-material-design: true

Source Code

  • Inside our lib folder is where we store all the meat and potatoes of our app.
  • lib/main.dart
  • lib/app/modules/home
  • lib/app/modules/home/bindings/home_binding.dart
import 'package:get/get.dart';

import '../controllers/home_controller.dart';

class HomeBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut<HomeController>(
      () => HomeController(),
    );
  }
}
  • lib/app/modules/home/controllers/home_controller.dart
import 'package:flutter/material.dart';
import 'package:flutter_theme_with_getx/app/theme/controller/theme_controller.dart';
import 'package:get/get.dart';

class HomeController extends GetxController
    with GetSingleTickerProviderStateMixin {
  final ThemeController _themeController = Get.find<ThemeController>();

  Rx<String> currentModeName = ''.obs;

  RxBool isDarkMode = false.obs; // Current Theme Stage

  //! Not Related To Theme> Just for Animation
  late Color textColor;
  double fontSize = 20;
  late AnimationController animationController;
  //! <Not Related To Theme Just for Animation

  @override
  void onInit() {
    //Getting theme Stage from ThemeController when homeView initialized
    isDarkMode.value = _themeController.isDarkTheme;
    currentModeName.value = _themeController.isDarkTheme ? 'Dark' : 'Light';

    //! Not Related To Theme > Just for Animation
    animationController = AnimationController(
        vsync: this, duration: const Duration(milliseconds: 430));
    animationController.reset();
    textColor = isDarkMode.value ? Colors.white : Colors.red;
    fontSize = isDarkMode.value ? 30 : 20;
    //! <Not Related To Theme Just for Animation

    super.onInit();
  }

  // Change Theme  Method That will call From HomeView
  void changeAppTheme() => _changeTheme();

  // Toggleing the Theme
  bool toggleTheme() {
    _changeTheme();
    return isDarkMode.value;
  }

  // Changeing Vale for Animation
  void _animate() {
    if (isDarkMode.value) {
      fontSize = 30;
      textColor = Colors.white;
      animationController.reverse();
    } else {
      fontSize = 20;
      textColor = Colors.red;
      animationController.forward();
    }
  }

  // Calling the changeTheme Method from ThemeController
  void _changeTheme() {
    _themeController.changeTheme(
      isDarkMode: isDarkMode,
      modeName: currentModeName,
    );
    _animate();
  }

  @override
  void onClose() {
    animationController.dispose();
    super.onClose();
  }
}
  • lib/app/modules/home/views/home_view.dart
// import 'package:flutter/material.dart';
import 'dart:math';

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

import '../controllers/home_controller.dart';

class HomeView extends GetView<HomeController> {
  const HomeView({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter Theme'),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            AnimatedBuilder(
              animation: controller.animationController,
              builder: (context, child) {
                return Transform.rotate(
                  angle: controller.animationController.value * 1 * pi,
                  child: child,
                );
              },
              child: Icon(
                controller.isDarkMode.value
                    ? Icons.dark_mode
                    : Icons.light_mode,
                size: 100,
              ),
            ),
            SizedBox(
              height: 50,
              child: Center(
                child: AnimatedDefaultTextStyle(
                    curve: Curves.easeInOut,
                    duration: const Duration(milliseconds: 500),
                    style: GoogleFonts.ubuntuMono(
                      fontSize: controller.fontSize,
                      color: controller.textColor,
                      fontWeight: FontWeight.w900,
                    ),
                    child:
                        Text(controller.currentModeName.value.toUpperCase())),
              ),
            ),
            Text(
              'Current theme',
              style: Theme.of(context).textTheme.headline4,
            ),
            SelectableText(
              'github.com/Monzim/flutter_theme_with_getx',
              style: Theme.of(context).textTheme.overline,
            ),
            const SizedBox(height: 20),
            CupertinoSwitch(
              value: controller.isDarkMode.value,
              onChanged: (bool val) {
                controller.toggleTheme();
                Get.snackbar(
                  '',
                  '',
                  maxWidth: 300,
                  titleText: Text(
                    'App Theme Changed',
                    textAlign: TextAlign.center,
                    style: Theme.of(context).textTheme.bodyText2,
                  ),
                  messageText: Text(
                    'to ${controller.currentModeName.value.toUpperCase()}',
                    textAlign: TextAlign.center,
                    style: Theme.of(context).textTheme.bodyText2,
                  ),
                  snackStyle: SnackStyle.FLOATING,
                  // maxWidth: 150,
                  mainButton: TextButton(
                    style: TextButton.styleFrom(primary: Colors.black),
                    onPressed: () {
                      controller.changeAppTheme();
                      Get.back();
                    },
                    child: Text(
                      'Revert',
                      textAlign: TextAlign.center,
                      style: Theme.of(context).textTheme.button,
                    ),
                  ),
                  backgroundColor:
                      controller.isDarkMode.value ? Colors.white : Colors.black,
                  snackPosition: SnackPosition.BOTTOM,
                );
              },
            ),
            const SizedBox(height: 2),
            ElevatedButton(
                onPressed: () {
                  controller.changeAppTheme();
                  if (Get.isOverlaysOpen) {
                    Get.back();
                  }
                  Get.snackbar(
                    '',
                    '',
                    maxWidth: 300,
                    titleText: Text(
                      'App Theme Changed',
                      textAlign: TextAlign.center,
                      style: Theme.of(context).textTheme.bodyText2,
                    ),
                    messageText: Text(
                      'to ${controller.currentModeName.value.toUpperCase()}',
                      textAlign: TextAlign.center,
                      style: Theme.of(context).textTheme.bodyText2,
                    ),
                    snackStyle: SnackStyle.FLOATING,
                    // maxWidth: 150,
                    mainButton: TextButton(
                      style: TextButton.styleFrom(primary: Colors.black),
                      onPressed: () {
                        controller.changeAppTheme();
                        Get.back();
                      },
                      child: Text(
                        'Revert',
                        textAlign: TextAlign.center,
                        style: Theme.of(context).textTheme.button,
                      ),
                    ),
                    backgroundColor: controller.isDarkMode.value
                        ? Colors.white
                        : Colors.black,
                    snackPosition: SnackPosition.BOTTOM,
                  );
                },
                child: const Text('Change Theme')),
            const SizedBox(height: 5),
          ],
        ),
      ),
    );
  }
}
  • lib/app/modules/initial/bindings/initial_binding.dart
import 'package:flutter_theme_with_getx/app/theme/controller/theme_controller.dart';
import 'package:get/get.dart';

import '../controllers/initial_controller.dart';

class InitialBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut<ThemeController>(() => ThemeController());
    Get.lazyPut<InitialController>(() => InitialController());
  }
}
  • lib/app/modules/initial/controllers/initial_controller.dart
import 'package:get/get.dart';

class InitialController extends GetxController {}
  • lib/app/routes/app_pages.dart
import 'package:get/get.dart';

import '../modules/home/bindings/home_binding.dart';
import '../modules/home/views/home_view.dart';

part 'app_routes.dart';

class AppPages {
  AppPages._();

  static const INITIAL = Routes.HOME;

  static final routes = [
    GetPage(
      name: _Paths.HOME,
      page: () => const HomeView(),
      binding: HomeBinding(),
    ),
    // GetPage(
    //   name: _Paths.INITIAL,
    //   page: () => InitialView(),
    //   binding: InitialBinding(),
    // ),
  ];
}
  • lib/app/routes/app_routes.dart
part of 'app_pages.dart';
// DO NOT EDIT. This is code generated via package:get_cli/get_cli.dart

abstract class Routes {
  Routes._();
  static const HOME = _Paths.HOME;
  // static const INITIAL = _Paths.INITIAL;
}

abstract class _Paths {
  _Paths._();
  static const HOME = '/home';
  // static const INITIAL = '/initial';
}
  • lib/app/theme/controller/theme_controller.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:hive_flutter/hive_flutter.dart';

class ThemeController extends GetxController {
  late bool isDarkTheme;
  late bool themeHiveSetting;

  // HiveBox for storing the theme setting
  final Box<dynamic> settingsHiveBox = Hive.box('settings');

  //! Getting Theme Stage From HiveBox and Set it to the ThemeMode this will be used in main.dart file
  ThemeMode get themeStateFromHiveSettingBox =>
      _getThemeFromHiveBox() ? ThemeMode.dark : ThemeMode.light;

  @override
  void onInit() {
    //! Getting the Theme State from the Hive Box and save it to the variable
    isDarkTheme = _getThemeFromHiveBox();
    super.onInit();
  }

  // private Method to Get HiveBox Storage theme Setting value adn Return it
  bool _getThemeFromHiveBox() {
    themeHiveSetting =
        settingsHiveBox.get('isDarkMode', defaultValue: Get.isDarkMode);
    print(themeHiveSetting);
    return themeHiveSetting;
  }

  // private Method to update HiveBox Storage theme Setting value
  void _updateHiveThemeSetting(bool boolData) {
    settingsHiveBox.put('isDarkMode', boolData);
  }

  // Method to change the Theme State when the user call it via Theme Chaneg Button
  void changeTheme({
    required RxBool isDarkMode,
    required Rx<String> modeName,
  }) {
    if (Get.isDarkMode) {
      modeName.value = 'light';
      isDarkMode.value = false;
      isDarkTheme = false;
      _updateHiveThemeSetting(false);
      _changeThemeMode(ThemeMode.light);
    } else {
      modeName.value = 'dark';
      isDarkMode.value = true;
      isDarkTheme = true;
      _updateHiveThemeSetting(true);
      _changeThemeMode(ThemeMode.dark);
    }
  }

  //Private Method to change theme
  void _changeThemeMode(ThemeMode themeMode) => Get.changeThemeMode(themeMode);
}
  • lib/app/theme/element/text_theme.dart
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';

// Custom Text Styles Class For Both Dark and Light Theme
class CustomTextTheme {
  //! Default Font is GoogleFonts.Ubuntu You can change it as your Need

  static const _textColorLight =
      Color(0xFF000000); // Light Theme Default Text Color
  static const _textColorDark =
      Color(0xFFFFFFFF); // Light Theme Default Text Color

  static TextTheme get textThemeLight {
    return _textTheme(textColor: _textColorLight);
  }

  static TextTheme get textThemeDark {
    return _textTheme(textColor: _textColorDark);
  }

  // Private Method For Text Theme so that we can change the vale for Both Dark And Light Theme
  static TextTheme _textTheme({required Color textColor}) {
    const FontWeight _light = FontWeight.w300;
    const FontWeight _medium = FontWeight.w500;
    const FontWeight _regular = FontWeight.w400;

    return TextTheme(
      headline1: GoogleFonts.ubuntu(
        fontSize: 96,
        color: textColor,
        fontWeight: _light,
        letterSpacing: -1.5,
      ),
      headline2: GoogleFonts.ubuntu(
        color: textColor,
        fontSize: 60,
        fontWeight: _light,
        letterSpacing: -0.5,
      ),
      headline3: GoogleFonts.ubuntu(
        color: textColor,
        fontSize: 48,
        fontWeight: _regular,
        letterSpacing: 0.0,
      ),
      headline4: GoogleFonts.ubuntu(
        color: textColor,
        fontSize: 34,
        fontWeight: _regular,
        letterSpacing: 0.25,
      ),
      headline5: GoogleFonts.ubuntu(
        color: textColor,
        fontSize: 24,
        fontWeight: _regular,
        letterSpacing: 0.0,
      ),
      headline6: GoogleFonts.ubuntu(
        color: textColor,
        fontSize: 20,
        fontWeight: _medium,
        letterSpacing: 0.15,
      ),
      bodyText1: GoogleFonts.ubuntu(
        color: textColor,
        fontSize: 16,
        fontWeight: _regular,
        letterSpacing: 0.5,
      ),
      bodyText2: GoogleFonts.ubuntu(
        color: textColor,
        fontSize: 14,
        fontWeight: _regular,
        letterSpacing: 0.25,
      ),
      button: GoogleFonts.ubuntu(
        color: textColor,
        fontSize: 14,
        fontWeight: _medium,
        letterSpacing: 1.25,
      ),
      caption: GoogleFonts.ubuntu(
        color: textColor,
        fontSize: 12,
        fontWeight: _regular,
        letterSpacing: 0.4,
      ),
      overline: GoogleFonts.ubuntu(
        color: textColor,
        fontSize: 10,
        fontWeight: _regular,
        letterSpacing: 1.5,
      ),
    );
  }
}
  • lib/app/theme/dark_theme.dart
import 'package:flutter/material.dart';

import 'element/text_theme.dart';

// ignore: non_constant_identifier_names
ThemeData DarkThemeData() {
  return ThemeData(
    brightness: Brightness
        .dark, //Setting the Brightness to Dark  so that this can be used as Dark ThemeData
    scaffoldBackgroundColor: Colors.black,
    textTheme:
        CustomTextTheme.textThemeDark, //Setting the Text Theme to DarkTextTheme

    appBarTheme: const AppBarTheme(centerTitle: true),

    elevatedButtonTheme: ElevatedButtonThemeData(
        style: ButtonStyle(
      backgroundColor: MaterialStateProperty.all<Color>(Colors.grey),
    )),
    //! You Can Set All Your Custom Dark Theme Here
  );
}
  • lib/app/theme/light_theme.dart
import 'package:flutter/material.dart';

import 'element/text_theme.dart';

// ignore: non_constant_identifier_names
ThemeData LightThemeData() {
  return ThemeData(
    brightness: Brightness
        .light, //Setting the Brightness to light  so that this can be used as Light ThemeData
    scaffoldBackgroundColor: Colors.white,
    textTheme: CustomTextTheme
        .textThemeLight, //Setting the Text Theme to LightTextTheme

    appBarTheme: const AppBarTheme(
      backgroundColor: Colors.deepOrange,
      elevation: 0,
      centerTitle: true,
    ),

    elevatedButtonTheme: ElevatedButtonThemeData(
        style: ButtonStyle(
      backgroundColor: MaterialStateProperty.all<Color>(Colors.black),
    )),
  );
}
  • lib/app/theme/theme.dart
import 'theme_p.dart';

// Custom Theme Class
class CustomTheme {
  static final lightTheme = LightThemeData();
  static final darkTheme = DarkThemeData();
}
  • lib/app/theme/theme_p.dart
export 'light_theme.dart';
export 'dark_theme.dart';

Output Screenshots

Inspired by a GitHub repository by monzim, check him out!!!

SHARE A Flutter App with Dark and Light Theme Mini Project with Source Code

You may also like...

Leave a Reply

Your email address will not be published.

Share