Theming in Flutter — Dark & Light Modes

In this article, we will see how to Theme our apps in Flutter.

As you know Google and Apple has released Dark Mode and Light Modes in their latest OS releases in Android 10 and iOS 13. So we have to make sure that our apps works perfectly when the user switch modes in their devices.

Watch Youtube Tutorial

We have a simple screen here with just a ListView. So we will be trying to theme this screen based on the Device theme.



import 'package:provider/provider.dart';

import 'AppNotifier.dart';



class ThemeDemo extends StatefulWidget {

@override

ThemeDemoState createState() => ThemeDemoState();

}



class ThemeDemoState extends State<ThemeDemo> {



@override

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(

elevation: 0,

title: Text('Flutter Themes'),

leading: Icon(Icons.menu),

),

body: Container(

child: ListView.builder(

itemCount: 10,

itemBuilder: (context, pos) {

return Card(

elevation: 0,

child: ListTile(

title: Text(

"Title $pos",

),

subtitle: Text(

"Subtitle $pos",

),

leading: Icon(

Icons.alarm,

),

trailing: Icon(

Icons.chevron_right,

),

),

);

},

),

),

);

}

} import 'package:flutter/material.dart';import 'package:provider/provider.dart';import 'AppNotifier.dart';class ThemeDemo extends StatefulWidget {ThemeDemoState createState() => ThemeDemoState();class ThemeDemoState extends State {Widget build(BuildContext context) {return Scaffold(appBar: AppBar(elevation: 0,title: Text('Flutter Themes'),leading: Icon(Icons.menu),),body: Container(child: ListView.builder(itemCount: 10,itemBuilder: (context, pos) {return Card(elevation: 0,child: ListTile(title: Text("Title $pos",),subtitle: Text("Subtitle $pos",),leading: Icon(Icons.alarm,),trailing: Icon(Icons.chevron_right,),),);},),),);

Now we will add this screen in the main.dart as the ‘home’.



runApp(

HomeApp(),

);

}



class HomeApp extends StatelessWidget {

@override

Widget build(BuildContext context) {

return MaterialApp(

title: 'Flutter Tutorials',

debugShowCheckedModeBanner: false,

home: ThemeDemo(),

);

}

} void main() {runApp(HomeApp(),);class HomeApp extends StatelessWidget {Widget build(BuildContext context) {return MaterialApp(title: 'Flutter Tutorials',debugShowCheckedModeBanner: false,home: ThemeDemo(),);

If you run the application now, you will see the default theme, which is the Light Theme.

Now let’s add a theme to our parent ‘MaterialApp’ widget.

MaterialApp(

title: 'Flutter Theming Tutorials',

debugShowCheckedModeBanner: false,

theme: ThemeData.light(),

home: ThemeDemo(),

);

Even if you specify the ThemeData.light() theme, the UI will not change because the default theme applied is the light theme.

Now let’s apply the Dark Theme.

MaterialApp(

title: 'Flutter Theming Tutorials',

debugShowCheckedModeBanner: false,

theme: ThemeData.light(),

darkTheme: ThemeData.dark(),

home: ThemeDemo(),

);

Here we have applied the Dark Theme, so if we switch the Device theme from light to Dark in the Settings, our UI will update. Be default, all whites will turn black and all blacks will turn whites, this is provided by the Flutter framework.

Customize Themes

So now we know that the ‘theme’ property is accepting the ThemeData Object. So let’s go ahead a create a custom ThemeData.

For that, I am creating a new file named “AppTheme.dart” and create two themes for Light and Dark Themes.

import 'package:flutter/material.dart';



class AppTheme {

//

AppTheme._();



static final ThemeData lightTheme = ThemeData(

scaffoldBackgroundColor: Colors.teal,

appBarTheme: AppBarTheme(

color: Colors.teal,

iconTheme: IconThemeData(

color: Colors.white,

),

),

colorScheme: ColorScheme.light(

primary: Colors.white,

onPrimary: Colors.white,

primaryVariant: Colors.white38,

secondary: Colors.red,

),

cardTheme: CardTheme(

color: Colors.teal,

),

iconTheme: IconThemeData(

color: Colors.white54,

),

textTheme: TextTheme(

title: TextStyle(

color: Colors.white,

fontSize: 20.0,

),

subtitle: TextStyle(

color: Colors.white70,

fontSize: 18.0,

),

),

);



static final ThemeData darkTheme = ThemeData(

scaffoldBackgroundColor: Colors.black,

appBarTheme: AppBarTheme(

color: Colors.black,

iconTheme: IconThemeData(

color: Colors.white,

),

),

colorScheme: ColorScheme.light(

primary: Colors.black,

onPrimary: Colors.black,

primaryVariant: Colors.black,

secondary: Colors.red,

),

cardTheme: CardTheme(

color: Colors.black,

),

iconTheme: IconThemeData(

color: Colors.white54,

),

textTheme: TextTheme(

title: TextStyle(

color: Colors.white,

fontSize: 20.0,

),

subtitle: TextStyle(

color: Colors.white70,

fontSize: 18.0,

),

),

);

}

In the above code, as you can see we have two variables for Light and Dark Themes where we are customizing some of its properties such as ‘scaffoldBackgroundColor’, ‘appBarTheme’ etc.

scaffoldBackgroundColor will change the background color of the screen, appBarTheme will change the color of you AppBar and similarly for other styles.

Manually Switching Themes

Here the idea is to broadcast the theme change when the user changes. Now we will need a package which can do that.

So open your pubspec.yaml file and add the ‘provider’ package.

Run the flutter packages get in the terminal inside your project and install the package.

Now we have to write a class and a method to broadcast the Theme changes. So lets create a new class named “AppStateNotifier’

import 'package:flutter/material.dart';



class AppStateNotifier extends ChangeNotifier {

//

bool isDarkMode = false;



void updateTheme(bool isDarkMode) {

this.isDarkMode = isDarkMode;

notifyListeners();

}

}

Now we will add a Switch Widget in the UI to switch between the Themes.

Switch(

value: Provider.of<AppStateNotifier>(context).isDarkMode,

onChanged: (boolVal) {

Provider.of<AppStateNotifier>(context).updateTheme(boolVal);

},

)

Now we need to add a Listener to listen to the changes and update the theme. We have to go to our Top most widget and update the code like this.



runApp(

ChangeNotifierProvider<AppStateNotifier>(

builder: (context) => AppStateNotifier(),

child: HomeApp(),

),

);

}



class HomeApp extends StatelessWidget {

@override

Widget build(BuildContext context) {

return Consumer<AppStateNotifier>(

builder: (context, appState, child) {

return MaterialApp(

title: 'Flutter Theming Tutorials',

debugShowCheckedModeBanner: false,

theme: AppTheme.lightTheme, // ThemeData(primarySwatch: Colors.blue),

darkTheme:

AppTheme.darkTheme, // ThemeData(primarySwatch: Colors.blue),

home: ThemeDemo(),

themeMode: appState.isDarkMode ? ThemeMode.dark : ThemeMode.light,

);

},

);

}

} void main() {runApp(ChangeNotifierProvider (builder: (context) => AppStateNotifier(),child: HomeApp(),),);class HomeApp extends StatelessWidget {Widget build(BuildContext context) {return Consumer (builder: (context, appState, child) {return MaterialApp(title: 'Flutter Theming Tutorials',debugShowCheckedModeBanner: false,theme: AppTheme.lightTheme, // ThemeData(primarySwatch: Colors.blue),darkTheme:AppTheme.darkTheme, // ThemeData(primarySwatch: Colors.blue),home: ThemeDemo(),themeMode: appState.isDarkMode ? ThemeMode.dark : ThemeMode.light,);},);

Here the HomeApp is surrounded by ChangeNotifierProvider Widget which receives the changes and sends it to the ‘Consumer’ widget to Consume it and use it to make the changes. In the above code you can see the ‘themeMode’ property which is updated based on the appState variable. When the Switch widget turns on, it will send the boolean value true to the Listeners and finally to the Consumer Widget.

themeMode: appState.isDarkMode ? ThemeMode.dark : ThemeMode.light,

Update the Text Themes

Now we know the theme which is set in the application with the help of Theme.of(context) inherited widget.

So to update the text themes or any other theme which is declared in our Custom Themes, you can get access to it with the help of Theme.of(context).

For example. the text widgets can be applied styles like this.

Text(

"Title $pos",

style: Theme.of(context).textTheme.title,

),

and Icons can be set like this.

Icon(

Icons.alarm,

color: Theme.of(context).iconTheme.color,

),

Complete Source Code

The complete source code is available in the below location

https://bitbucket.org/vipinvijayan1987/tutorialprojects/src/master/FlutterTutorialProjects/flutter_demos/lib/widgets/ThemeDemo/

Please leave your valuable comments below.

Hit the clap button if you find this article useful.

Thanks for reading.

If you find this article useful, please give me some claps.

Do you know you can clap 50 times. Please do if I deserve it.