DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Building A Simple AI Application in 2023 for Fun and Profit
  • Angular vs. Flutter for Web App Development: Know Which One Is Best?
  • Stateless vs. Stateful Widgets: Make the Right Choice for Your Flutter App
  • Guide to E-Commerce Mobile App Development: Steps, Features, and Costs

Trending

  • Jakarta EE 12: Entering the Data Age of Enterprise Java
  • Reactive Ops to Autonomous Infrastructure: How Agentic AI Is Redefining Modern DevOps
  • Why Your RAG Pipeline Will Fail Without an MCP Server
  • How Reactive Scaling Drains Your Cloud Budget Without Warning
  1. DZone
  2. Coding
  3. Frameworks
  4. Flutter Theme Made Easy

Flutter Theme Made Easy

Flutter provides you with a way to customize your app theme. It is extremely focused on material design, but you can still customize it to fit your needs.

By 
Gautier Siclon user avatar
Gautier Siclon
·
Nov. 08, 23 · Tutorial
Likes (10)
Comment
Save
Tweet
Share
1.8K Views

Join the DZone community and get the full member experience.

Join For Free

Flutter provides you with a way to customize your app theme. It is extremely focused on material design, but you can still customize it to fit your needs.

The Problem

Flutter provides you with a great theme to let you customize your app. The problem is when you want to start getting out of material and customize your app theme. Most designers will want to customize the theme to fit their needs and tastes. 

You create your theme directly without any factory. This means you will have many developers copy and paste colors throughout the app and the themeData file.

You can't switch the theme without restarting the app (dark/light?). You don't have a way to set different themes for different platforms. The good news is that we can fix all of this.

Handling Dark and Light Theme

Switching from light to dark mode should be easy.

The best way to do this is not to duplicate your theme but to create a factory that will create the theme from a color palette.

Flutter theme light and dark

Flutter and Material provide you with a nice, logical way to handle an app theme — every color is an 'on' color. Meaning that if you have a white background, you should have a black text color.

Switching from light to dark should only rely on switching some colors.

You should not have to handle a case in your code.

Limit the Number of Colors

The more colors you have, the more difficult it will be to maintain your app. Simplicity is often the best way to go.

Instead of having a primary, secondary, accent, secondaryAccent, ... try making your app with one or two colors.

The more colors you incorporate, the more challenging it becomes to maintain your app. Simplicity is often the best approach. Instead of using primary, secondary, accent, secondaryAccent, and so forth, consider designing your app with just one or two colors.

(Please note that black, white, and greys are exceptions and are not considered as colors.)

Flutter color palette

For example, you can check some of the most popular apps. Facebook, Instagram, Twitter, YouTube, etc... They don't use a lot of colors.

Creating a Theme Factory

As we want to create our theme for different platforms or different color palettes, we will create a factory.

Dart
 
abstract class ApparenceKitThemeDataFactory {
  const ApparenceKitThemeDataFactory();

  ApparenceKitThemeData build({
    required ApparenceKitColors colors,
    required ApparenceKitTextTheme defaultTextStyle,
  });
}


This factory will take a color palette and a default text theme and will create a theme.

The default text theme contains the default text style and fonts for all our text. As for the colors, I also recommend limiting the number of fonts you use.

Our designer at Apparence tends to limit his usage to two fonts. (There is some website that gives you inspirations for two fonts that go well together...)

Using Our Factory

Now that we have our factory, we can use it to create our theme.

Dart
 
class UniversalThemeFactory extends ApparenceKitThemeDataFactory {
  const UniversalThemeFactory();

  @override
  ApparenceKitThemeData build({
    required ApparenceKitColors colors,
    required ApparenceKitTextTheme defaultTextStyle,
  }) {
    return ApparenceKitThemeData(
      colors: colors,
      defaultTextTheme: defaultTextStyle,
      materialTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: colors.primary).copyWith(
          surface: colors.surface,
          onSurface: colors.onSurface,
          background: colors.background,
          onBackground: colors.onBackground,
          primary: colors.primary,
          error: colors.error,
        ),
        elevatedButtonTheme: elevatedButtonTheme(
          colors: colors,
          textTheme: defaultTextStyle,
        ),
        inputDecorationTheme: inputDecorationTheme(
          colors: colors,
          textTheme: defaultTextStyle,
        ),
        textTheme: textTheme(
          colors: colors,
          defaultTextStyle: defaultTextStyle,
        ),
      ),
      ...
    );


As you can see, we are using the color palette and the default text theme to create our theme. Now, changing colors or text style won't be done here.

We have defined our own color palette and default text files separately.

Providing Our Theme Through the App

As we want to access our theme from anywhere in our app we will use an InheritedNotifier. This will allow us to access our theme from the BuildContext. But also to switch the mode of our theme without restarting the app.

Dart
 
/// We use this to access the theme from the BuildContext in all our widgets
/// We don't use riverpod here so we can get the theme from the context and regular widgets
class ThemeProvider extends InheritedNotifier<AppTheme> {
  const ThemeProvider({
    super.key,
    super.notifier,
    required super.child,
  });

  @override
  bool updateShouldNotify(covariant InheritedNotifier<AppTheme> oldWidget) {
    ...
  }

  static AppTheme of(BuildContext context) =>
      context.dependOnInheritedWidgetOfExactType<ThemeProvider>()!.notifier!;
}


Using Our Theme ThemeProvider

Now that we have our ThemeProvider we can use it in our app. It will be above our MaterialApp.

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

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return ThemeProvider(
      notifier: AppTheme.uniform(
        themeFactory: const UniversalThemeFactory(),
        lightColors: ApparenceKitColors.light(),
        darkColors: ApparenceKitColors.dark(),
        textTheme: ApparenceKitTextTheme.build(),
        defaultMode: ThemeMode.light,
      ),
      child: Builder(builder: (context) {
        return MaterialApp(
          title: 'Flutter Pro Starter Kit',
          initialRoute: 'home',
          theme: ThemeProvider.of(context).light,
          darkTheme: ThemeProvider.of(context).dark,
          themeMode: ThemeProvider.of(context).mode,


If you don't want to use dark mode, you can just remove it. This way, we can access our theme from anywhere in our app.

Using, for example: 

ThemeProvider.of(context).current


Or still using the regular Theme.of(context)

Theme.of(context).textTheme.headline1


Creating Theme Shortcuts

As we want to access our theme from anywhere in our app, we will create some shortcuts. This will allow us to access our theme from the BuildContext. But also to switch the mode of our theme without restarting the app.

Dart
 
extension ThemeExtension on BuildContext {
  // access the theme from anywhere in the app using context.theme  
  ApparenceKitThemeData get theme => ThemeProvider.of(this).current;
  // access the color palette from anywhere in the app using context.colors  
  ApparenceKitColors get colors => ThemeProvider.of(this).current.colors;
  // access the text theme from anywhere in the app using context.textTheme
  ApparenceKitTextTheme get textTheme => ThemeProvider.of(this).current.textTheme;
  // access the theme mode from anywhere in the app using context.themeMode
  ThemeMode get themeMode => ThemeProvider.of(this).mode;
  // toggle the theme mode from anywhere in the app using context.toggleTheme
  void toggleTheme() => ThemeProvider.of(this).toggle();
}


Conclusion

There are many things to say about handling themes from design to code.
Multiplatform theme, gradients, shadows,...

I hope this article will help you start creating a great multiplatform theme. This way of handling the theme is the one we use at Apparence, and we included it in our starter kit.

Design app Flutter (software)

Published at DZone with permission of Gautier Siclon. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Building A Simple AI Application in 2023 for Fun and Profit
  • Angular vs. Flutter for Web App Development: Know Which One Is Best?
  • Stateless vs. Stateful Widgets: Make the Right Choice for Your Flutter App
  • Guide to E-Commerce Mobile App Development: Steps, Features, and Costs

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook