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
Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
View Events Video Library
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

UK-US Data Bridge: Join TechnologyAdvice and OneTrust as they discuss the UK extension to the EU-US Data Privacy Framework (DPF).

Migrate, Modernize and Build Java Web Apps on Azure: This live workshop will cover methods to enhance Java application development workflow.

Kubernetes in the Enterprise: The latest expert insights on scaling, serverless, Kubernetes-powered AI, cluster security, FinOps, and more.

A Guide to Continuous Integration and Deployment: Learn the fundamentals and understand the use of CI/CD in your apps.

Related

  • 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
  • How to Build a Video Streaming App With Screen Sharing Using Flutter

Trending

  • Build ChatGPT 2.0 With React JS
  • A Tale of Two Intersecting Quality Attributes: Security and Performance
  • Smoke Testing and the Spaceship Analogy
  • Leveraging "INSERT INTO ... RETURNING": Practical Scenarios
  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.

Gautier Siclon user avatar by
Gautier Siclon
·
Nov. 08, 23 · Tutorial
Like (2)
Save
Tweet
Share
1.2K 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

  • 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
  • How to Build a Video Streaming App With Screen Sharing Using Flutter

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

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 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: