Mastering Theme Management with Provider in Flutter From Basics to Pro

Flutter Theme Management using Provider Package

Introduction

Flutter, Google's UI toolkit, allows developers to create beautiful, responsive applications for mobile, web, and desktop platforms using a single codebase. One of the key aspects of building an engaging app is managing the app's theme and colors. In this blog post, we will explore how to achieve this using the Provider package, a popular state management solution for Flutter applications.

Prerequisites

Before we dive into the implementation, make sure you have the following installed:

  • Flutter SDK
  • Flutter IDE (like Android Studio or Visual Studio Code)
  • Basic understanding of Flutter widgets and state management concepts

Step 1: Creating a New Flutter Project

Let's start by creating a new Flutter project. Open your terminal and run the following command:

flutter create flutter_theme_provider

Navigate to the project directory:

cd flutter_theme_provider

Step 2: Adding Dependencies

We'll need to add the Provider package to our project. Open the pubspec.yaml file and add the following lines under the dependencies section:

dependencies:
  flutter:
    sdk: flutter
  provider: ^5.0.0
  

Save the file and run the following command to fetch the dependencies:

flutter pub get

Step 3: Implementing the ThemeProvider Class

Create a new Dart file named theme_provider.dart inside the lib directory. This file will contain the implementation of the ThemeProvider class:

import 'package:flutter/material.dart';

class ThemeProvider extends ChangeNotifier{
  ThemeData themeData = ThemeData(
      colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.teal,
      ),

      textTheme: const TextTheme(
        displayLarge: TextStyle(fontWeight: FontWeight.w800, fontSize: 25),
        displayMedium: TextStyle(fontWeight: FontWeight.w600, fontSize: 20),
        displaySmall: TextStyle(fontSize: 15),
      ),
      useMaterial3: true
  );

  setDarkMode(){
    Color seedColor = themeData.colorScheme.primaryContainer;

    themeData = themeData.copyWith(
      colorScheme: ColorScheme.fromSeed(
          seedColor: seedColor,
        brightness: Brightness.dark
      )
    );
    notifyListeners();
  }

  setLightMode(){
    Color seedColor = themeData.colorScheme.primaryContainer;

    themeData = themeData.copyWith(
        colorScheme: ColorScheme.fromSeed(
            seedColor: seedColor,
            brightness: Brightness.light
        )
    );
    notifyListeners();
  }

  changeColor(Color color){
    themeData = ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: color,
        ),

        textTheme: const TextTheme(
          displayLarge: TextStyle(fontWeight: FontWeight.w800, fontSize: 25),
          displayMedium: TextStyle(fontWeight: FontWeight.w600, fontSize: 20),
          displaySmall: TextStyle(fontSize: 15),
        ),
        useMaterial3: true
    );
    notifyListeners();
  }
}

  

Step 4: Implementing the Main Application

Replace the content of the lib/main.dart file with the following code:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'theme_provider.dart';

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => ThemeProvider()),
      ],
      child: const MyApp(),
    ),
  );
}

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


  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Musana Coding Journey',
      debugShowCheckedModeBanner: false,
      theme: Provider.of(context).themeData,
      home: const MyHomePage(title: 'Flutter Theme'),
    );
  }
}
  

Step 5: Building the UI

Let's continue implementing the _MyHomePageState class to build the UI for the home page. Replace the comment in the _MyHomePageState class with the following code

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State createState() => _MyHomePageState();
}

class _MyHomePageState extends State {

  List data = [];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Theme.of(context).colorScheme.background,
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(
            widget.title,
          style: Theme.of(context).textTheme.displayMedium?.copyWith(
            color: Theme.of(context).colorScheme.inverseSurface
          ),
        )
      ),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
                onPressed: (){
                  final themeProvider = Provider.of(context, listen: false);
                  themeProvider.setDarkMode();
                },
                child: Text(
                  "Dark Mode"
                )
            ),
            ElevatedButton(
                onPressed: (){
                  final themeProvider = Provider.of(context, listen: false);
                  themeProvider.setLightMode();
                },
                child: Text(
                    "Light Mode"
                )
            ),
            ElevatedButton(
                onPressed: (){
                  final themeProvider = Provider.of(context, listen: false);
                  themeProvider.changeColor(Colors.yellow);
                },
                child: Text(
                    "Yellow Color"
                )
            ),
            ElevatedButton(
                onPressed: (){
                  final themeProvider = Provider.of(context, listen: false);
                  themeProvider.changeColor(Colors.teal);
                },
                child: Text(
                    "Teal Color"
                )
            ),
            Container(
              height: 100,
              width: 100,
              color: Theme.of(context).colorScheme.primaryContainer,
            ),
            SizedBox(
              height: 10,
            ),
            Container(
              height: 100,
              width: 100,
              color: Theme.of(context).colorScheme.secondaryContainer,
            ),
            SizedBox(
              height: 10,
            ),
            Container(
              height: 100,
              width: 100,
              color: Theme.of(context).colorScheme.tertiaryContainer,
            ),
          ],
        ),
      ),
    );
  }

}
  

Step 7: Implementing Theme Changes (Continued)

In the setDarkMode() and setLightMode() methods, you can modify the theme data's brightness to achieve the desired effect. Similarly, the changeColor() method updates the primary color of the theme.

Conclusion:

In this blog post, we've learned how to manage the theme and colors of a Flutter application using the Provider package. We started by setting up a new Flutter project, adding the necessary dependencies, and creating a ThemeProvider class. We then integrated the theme provider into the main application, allowing users to switch between dark and light modes and change the primary color of the app. By using the Provider package, we've achieved a scalable and efficient way of managing the app's theme-related state, ensuring a consistent and visually appealing user experience. Remember, this is just the beginning of what you can achieve with Provider. You can extend the theme management further and experiment with different aspects of your app's state management.


Post a Comment

0 Comments