Implementing Custom Themes and Color Schemes in Flutter

Flutter’s theming system provides a powerful way to create consistent and customizable user interfaces. By implementing custom themes and color schemes, you can ensure that your app has a unique and branded look and feel. This post explores how to define custom themes, manage color schemes, and apply these themes to your Flutter application.

Understanding Themes in Flutter

A theme in Flutter defines the visual properties of your application, such as colors, text styles, and widget styling. Using themes ensures consistency across your app and simplifies the process of updating the app’s appearance.

Why Use Custom Themes and Color Schemes?

  • Consistency: Maintain a uniform look and feel throughout your app.
  • Customization: Tailor the app’s appearance to match your brand.
  • Maintainability: Easily update the app’s styling in one central location.
  • Dark/Light Mode Support: Implement different themes for various user preferences.

How to Implement Custom Themes and Color Schemes in Flutter

Follow these steps to create and apply custom themes in your Flutter app:

Step 1: Define Custom Color Schemes

First, define your custom color schemes. You can do this by creating ColorScheme instances that represent the various color roles in your app (e.g., primary, secondary, background).


import 'package:flutter/material.dart';

class AppColors {
  static const Color primaryColor = Color(0xFF3F51B5);
  static const Color secondaryColor = Color(0xFFE91E63);
  static const Color backgroundColor = Color(0xFFF5F5F5);
  static const Color textColor = Color(0xFF212121);
}

Step 2: Create a Custom Theme

Next, create a custom theme using the ThemeData class. This is where you specify the color scheme and other theme properties such as text styles, button styles, etc.


import 'package:flutter/material.dart';

ThemeData lightTheme = ThemeData(
  colorScheme: ColorScheme.light(
    primary: AppColors.primaryColor,
    secondary: AppColors.secondaryColor,
    background: AppColors.backgroundColor,
  ),
  textTheme: TextTheme(
    headline1: TextStyle(fontSize: 32.0, fontWeight: FontWeight.bold, color: AppColors.textColor),
    bodyText1: TextStyle(fontSize: 16.0, color: AppColors.textColor),
  ),
  elevatedButtonTheme: ElevatedButtonThemeData(
    style: ElevatedButton.styleFrom(
      primary: AppColors.primaryColor,
      onPrimary: Colors.white,
      padding: EdgeInsets.symmetric(horizontal: 32, vertical: 16),
      textStyle: TextStyle(fontSize: 18),
    ),
  ),
);

Similarly, create a dark theme:


ThemeData darkTheme = ThemeData(
  colorScheme: ColorScheme.dark(
    primary: AppColors.primaryColor,
    secondary: AppColors.secondaryColor,
    background: Color(0xFF303030),
  ),
  textTheme: TextTheme(
    headline1: TextStyle(fontSize: 32.0, fontWeight: FontWeight.bold, color: Colors.white),
    bodyText1: TextStyle(fontSize: 16.0, color: Colors.white),
  ),
  elevatedButtonTheme: ElevatedButtonThemeData(
    style: ElevatedButton.styleFrom(
      primary: AppColors.primaryColor,
      onPrimary: Colors.white,
      padding: EdgeInsets.symmetric(horizontal: 32, vertical: 16),
      textStyle: TextStyle(fontSize: 18),
    ),
  ),
);

Step 3: Apply the Theme to Your App

Apply the custom theme to your app using the Theme widget in your MaterialApp. This ensures that the theme is applied to all widgets in your app.


import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Custom Theme Example',
      theme: lightTheme, // Use lightTheme or darkTheme
      darkTheme: darkTheme, // Optional: For dark mode support
      themeMode: ThemeMode.system, // Follow system theme
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Custom Theme Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'Headline',
              style: Theme.of(context).textTheme.headline1,
            ),
            SizedBox(height: 20),
            Text(
              'Body Text',
              style: Theme.of(context).textTheme.bodyText1,
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {},
              child: Text('Click Me'),
            ),
          ],
        ),
      ),
    );
  }
}

Step 4: Theme Switching

To allow users to switch between light and dark themes, you can use a StatefulWidget and the setState method to update the theme.


import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State {
  ThemeMode _themeMode = ThemeMode.system;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Custom Theme Example',
      theme: lightTheme,
      darkTheme: darkTheme,
      themeMode: _themeMode,
      home: MyHomePage(
        onThemeChanged: (ThemeMode mode) {
          setState(() {
            _themeMode = mode;
          });
        },
      ),
    );
  }
}

class MyHomePage extends StatelessWidget {
  final Function(ThemeMode) onThemeChanged;

  MyHomePage({required this.onThemeChanged});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Custom Theme Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'Headline',
              style: Theme.of(context).textTheme.headline1,
            ),
            SizedBox(height: 20),
            Text(
              'Body Text',
              style: Theme.of(context).textTheme.bodyText1,
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {},
              child: Text('Click Me'),
            ),
            SizedBox(height: 20),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text('Light Mode'),
                Switch(
                  value: Theme.of(context).brightness == Brightness.light,
                  onChanged: (bool value) {
                    onThemeChanged(value ? ThemeMode.light : ThemeMode.dark);
                  },
                ),
                Text('Dark Mode'),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

Customizing Widgets with ThemeData

You can further customize individual widgets by overriding properties in the ThemeData. For example, to customize the appearance of the AppBar, you can set the appBarTheme property.


ThemeData lightTheme = ThemeData(
  colorScheme: ColorScheme.light(
    primary: AppColors.primaryColor,
    secondary: AppColors.secondaryColor,
    background: AppColors.backgroundColor,
  ),
  textTheme: TextTheme(
    headline1: TextStyle(fontSize: 32.0, fontWeight: FontWeight.bold, color: AppColors.textColor),
    bodyText1: TextStyle(fontSize: 16.0, color: AppColors.textColor),
  ),
  elevatedButtonTheme: ElevatedButtonThemeData(
    style: ElevatedButton.styleFrom(
      primary: AppColors.primaryColor,
      onPrimary: Colors.white,
      padding: EdgeInsets.symmetric(horizontal: 32, vertical: 16),
      textStyle: TextStyle(fontSize: 18),
    ),
  ),
  appBarTheme: AppBarTheme(
    backgroundColor: AppColors.primaryColor,
    titleTextStyle: TextStyle(color: Colors.white, fontSize: 20),
  ),
);

Conclusion

Implementing custom themes and color schemes in Flutter allows you to create visually appealing, consistent, and maintainable applications. By defining your own color schemes, customizing ThemeData, and applying themes to your MaterialApp, you can ensure that your app has a unique and branded look and feel. Supporting dark and light modes enhances user experience by allowing users to choose their preferred theme.