Skip to content

Theming

Lance Johnstone edited this page Apr 14, 2023 · 5 revisions

From v3.3 onwards you can set the theme of both the material and cupertino themes more succinctly by using the PlatformTheme widget.

PlatformTheme

package version >=3.3.0

For versions 3.3 and above you can change the app setup to the following. You no longer need to set the theme for the PlatformApp material and cupertino data fields.

final currentTheme = ThemeData.light(); // Change theme for your needs
PlatformProvider(
    builder: (context) => PlatformTheme(
        materialLightTheme: currentTheme,
        builder: (context) => 
            PlatformApp(
              title: 'Flutter Platform Widgets',
              home: _YourHomePage_(),
        ),
    ),
)

With `PlatformTheme` you can set the light and dark theme of both material and cupertino, but also set the `ThemeMode` for the application

```dart
PlatformTheme(
    themeMode: themeMode,
    materialLightTheme: materialLightTheme,
    materialDarkTheme: materialDarkTheme,
    cupertinoLightTheme: cupertinoLightTheme,
    cupertinoDarkTheme: cupertinoDarkTheme,
    builder: (context) => PlatformApp(...)
)

See below for how to create material and cupertino light and dark themes.

Properties on the PlatformTheme widget include:

Property Description
themeMode ThemeMode value of either light, dark or system
materialLightTheme The light theme for material
materialDarkTheme The dark theme for material
cupertinoLightTheme The light theme for cupertino
cupertinoDarkTheme The dark theme for cupertino
matchCupertinoSystemChromeBrightness Sets the SystemChrome brightness for cupertino based off the ThemeMode. Defaults to true
onThemeModeChanged When the ThemeMode changes via the PlatformTheme.of(context).themeMode property
builder (required) The main builder function which typically has the PlatformApp as its child

Theme mode

If you want the app to change from light to dark themes you can use the PlatformTheme.of(context).themeMode property from anywhere in your application.

PlatformElevatedButton(
    onPressed: () => PlatformTheme.of(context).themeMode = ThemeMode.dark,
    child: Text('Change to dark mode'),
)

If you need to store the currently set theme you can use the onThemeModeChanged callback. Saving externally to the application is not the responsibility of this library.

PlatformTheme(
    themeMode: initialThemeMode,
    onThemeModeChanged: (themeMode) { /* Store the changed theme mode here */ }
)

Cupertino theme

The simpliest way to get a cupertino theme in your app is to copy the values from the material theme and apply it to the PlatformApp.

final materialTheme = ThemeData.light(); 
final cupertinoTheme = MaterialBasedCupertinoThemeData(materialTheme: materialTheme);
PlatformProvider( 
  builder: (context) => PlatformTheme(
    materialLightTheme: materialTheme,
    cupertinoLightTheme: cupertinoTheme,
    builder: (context) => PlatformApp(
      title: 'Flutter Platform Widgets',
      home: _YourHomePage_(),
    ),
  ),
)

Dark mode: material

If you support dark mode, either via using the devices default system mode or having the user change the theme within your app you will need to ensure the theme data used is correct.

// Your default app's theme mode selection which can be changed.
const themeMode = ThemeMode.light;

final lightTheme = ThemeData.light();
final darkTheme = ThemeData.dark();

PlatformProvider( 
  builder: (context) => PlatformTheme(
    themeMode: lightTheme,
    materialLightTheme: lightTheme,
    materialDarkTheme: darkTheme,
    builder: (context) => PlatformApp(
      title: 'Flutter Platform Widgets',
      home: _YourHomePage_(),
    ),
  ),
)

Dark mode: cupertino

Using dark mode for cupertino is not as straight forward due to a number of issues raised with flutter. See #71590, #80860, #48438, #51899

These can be mitigated by having the cupertino theme customised...

final darkTheme = ThemeData.dark();
const darkDefaultCupertinoTheme = CupertinoThemeData(brightness: Brightness.dark);
final cupertinoDarkTheme = MaterialBasedCupertinoThemeData(
    materialTheme: darkTheme.copyWith(
      cupertinoOverrideTheme: CupertinoThemeData(
        brightness: Brightness.dark,
        barBackgroundColor:
            darkDefaultCupertinoTheme.barBackgroundColor,
        textTheme: CupertinoTextThemeData(
          navActionTextStyle: darkDefaultCupertinoTheme
              .textTheme.navActionTextStyle
              .copyWith(color: const Color(0xF0F9F9F9)),
          navLargeTitleTextStyle: darkDefaultCupertinoTheme
              .textTheme.navLargeTitleTextStyle
              .copyWith(color: const Color(0xF0F9F9F9)),
        ),
      ),
    ),
  );

Then just set the cupertino themes on the PlatformTheme. Ideally match the system chrome to match dark mode also.

PlatformProvider( 
  builder: (context) => PlatformTheme(
    cupertinoDarkTheme: cupertinoDarkTheme,
    PlatformApp(
      title: 'Flutter Platform Widgets',
      home: _YourHomePage_(),
    ),       
  ),
),

Change theme when platform changes

In cases where your app can switch between material and cupertino themes (much like the example from this project) you need to make sure the correct theme is kept the same.

Somewhere in your app you can just change the target platform...

// Perhaps this in a button click handler
final provider = PlatformProvider.of(context)!;

isMaterial(context)
    ? provider.changeToCupertinoPlatform()
    : provider.changeToMaterialPlatform();

This will rebuild the app with the new target platform however you need to make sure the correct theme is applied. Coupled with light and dark theme the complete theme setup probably should be this...

// Your default app's theme mode selection which can be changed.
const themeMode = ThemeMode.light;

final materialLightTheme = ThemeData.light();
final materialDarkTheme = ThemeData.dark();

final cupertinoLightTheme = MaterialBasedCupertinoThemeData(materialTheme: materialLightTheme);
const darkDefaultCupertinoTheme = CupertinoThemeData(brightness: Brightness.dark);
final cupertinoDarkTheme = MaterialBasedCupertinoThemeData(
    materialTheme: materialDarkTheme.copyWith(
      cupertinoOverrideTheme: CupertinoThemeData(
        brightness: Brightness.dark,
        barBackgroundColor:
            darkDefaultCupertinoTheme.barBackgroundColor,
        textTheme: CupertinoTextThemeData(
          navActionTextStyle: darkDefaultCupertinoTheme
              .textTheme.navActionTextStyle
              .copyWith(color: darkTheme.primaryColor),
          navLargeTitleTextStyle: darkDefaultCupertinoTheme
              .textTheme.navLargeTitleTextStyle
              .copyWith(color: const Color(0xF0F9F9F9)),
        ),
      ),
    ),
  );
      
PlatformProvider( 
  builder: (context) => PlatformTheme(
    themeMode: themeMode,
    materialLightTheme: materialLightTheme,
    materialDarkTheme: materialDarkTheme,
    cupertinoLightTheme: cupertinoLightTheme,
    cupertinoDarkTheme: cupertinoDarkTheme,
    builder: (context) =>
      PlatformApp(
        title: 'Flutter Platform Widgets',
        home: _YourHomePage_(),
      );
  ),
)