Customize and extend the Theme in Flutter

Photo by Sigmund on Unsplash

Customize and extend the Theme in Flutter

ยท

2 min read

Intro

Theming your Flutter app can be a challenge. This post will try to help you with the following:

  1. Provide sensible theme defaults for both light-mode and dark-mode.
  2. Customize the default theme.
  3. Extend the default theme.

This post comes with a sample app on Github. You might want to check it out because the code snippets in this post will make a lot more sense in the full context of the sample app.

Sample app: file.gif

Provide sensible theme defaults

If you want a quick start, I recommend using Mike Rydstrom's FlexColorScheme package.

This truly amazing package will give you sensible defaults for light-mode and dark-mode by providing at least one color.

app_theme.dart

ThemeData get _theme => _flexColorSchemeFactory(
  colors: FlexSchemeColor.from(
    primary: _basePrimaryColor,
    secondary: _baseSecondaryColor,
    error: _baseErrorColor,
  ),
  visualDensity: FlexColorScheme.comfortablePlatformDensity,
).toTheme

With that package initializing the theme in your will be as simple as:

main.dart

MaterialApp(
  title: 'Flutter Demo',
  theme: const AppThemeDataLight().theme,
  darkTheme: const AppThemeDataDark().theme,
   home: const MyHomePage(title: 'Flutter Demo Home Page'),
);

Customize the default theme

If you want to change the default theme, you can use the copyWith method on the ThemeData class. This method allows you to swap some parts of the theme with your own.

app_theme.dart

ThemeData get _theme => _flexColorSchemeFactory(
  colors: FlexSchemeColor.from(
    primary: _basePrimaryColor,
    secondary: _baseSecondaryColor,
    error: _baseErrorColor,
  ),
  visualDensity: FlexColorScheme.comfortablePlatformDensity,
).toTheme.copyWith(
  elevatedButtonTheme: _elevatedButtonThemeData(),
  outlinedButtonTheme: _outlinedButtonThemeData(),
  textButtonTheme: _textButtonThemeData(),
);

Extend the default theme

Sometimes you want to add custom colors and properties to the theme. With an extension method on ThemeData, this worked out pretty simple.

app_theme.dart

extension AppTheme on ThemeData {
  AppThemeData get appTheme => brightness == Brightness.dark
      ? const AppThemeDataDark()
      : const AppThemeDataLight();
}

With this extension method, getting custom colors and properties becomes really easy and intuitive.

'custom_button.dart'

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:yapb_theme/classes/app_theme.dart';

class CustomButton extends ConsumerWidget {
  const CustomButton(
    this.text, {
    Key? key,
    this.onPressed,
  }) : super(key: key);
  final String text;
  final VoidCallback? onPressed;

  @override
  Widget build(context, ref) {
    return OutlinedButton.icon(
      style: OutlinedButton.styleFrom(
        minimumSize: const Size(48, 48),
        padding: const EdgeInsets.all(8),
        side: Theme.of(context).appTheme.customButtonBorderSide,
      ),
      label: Text(
        text,
        style: TextStyle(
          fontWeight: FontWeight.w400,
          color: Theme.of(context).appTheme.customButtonColor,
        ),
      ),
      icon: Icon(
        Icons.flag,
        color: Theme.of(context).appTheme.customButtonColor,
      ),
      onPressed: onPressed,
    );
  }
}

About the sample app

In the sample app I have used the techniques from other posts in this blog. Key elements in this sample app are:

  1. Set up a mono repository with this dart script
  2. Replace getter and setter blocks with a oneliner when using ChangeNotifier.
  3. Flutter Riverpod
  4. Flex color scheme
ย