Custom Theme using Theme Extensions

By | December 16, 2022

Theme extensions were introduced in Flutter 3.

Theme Extensions in Flutter

But what are Theme Extensions?

As the name says, it helps to extend the inbuilt themes with our own extensions.

Let’s jump into an example

So when you create a flutter app, your basic root widget will look like this

 return MaterialApp(
title: 'Flutter Theme Extensions',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomePage(),
);

Here if you want to change the theme, you can basically customize the ThemeData, but you cannot add your own properties to it, like below.

return MaterialApp(
title: 'Flutter Theme Extensions',
theme: ThemeData(
primarySwatch: Colors.blue,
'myColor': '#FFAABBCC' // won't work
),
home: const HomePage(),
);

But then how do I do it if I want it?

Here comes the extensions.

return MaterialApp(
title: 'Flutter Theme Extensions',
theme: ThemeData(
primarySwatch: Colors.blue,
extensions: <ThemeExtension<dynamic>>[
// your colors and styles
],
),
home: const HomePage(),
);

Let’s see how we can create one. Create a new class named ‘MyColors’.

import 'package:flutter/material.dart';

@immutable
class MyColors extends ThemeExtension<MyColors> {
//
const MyColors({
required this.success,
required this.failure,
});

final Color? success;
final Color? failure;

@override
ThemeExtension<MyColors> copyWith({Color? success, Color? failure}) {
return MyColors(
success: success ?? this.success,
failure: failure ?? this.failure,
);
}

@override
ThemeExtension<MyColors> lerp(ThemeExtension<MyColors>? other, double t) {
if (other is! MyColors) {
return this;
}
return MyColors(
success: Color.lerp(success, other.success, t),
failure: Color.lerp(failure, other.failure, t),
);
}

@override
String toString() {
return 'MyColors(success: $success, failure: $failure)';
}

static const light = MyColors(
success: Color(0xFF28A745),
failure: Color.fromARGB(255, 128, 7, 35),
);

static const dark = MyColors(
success: Color.fromARGB(255, 226, 234, 8),
failure: Color.fromARGB(255, 205, 127, 18),
);
}

In the above code, I am declaring just two variables success and false.

And overrride two methods copyWith and lerp to return the new MyColor.

For convenience, declared two methods ‘light’ and ‘dark’ to use in different modes and initialized with colors for each mode.

Usage

Now in the UI, you can access it like any other Theme variable.

 Widget build(BuildContext context) {
final myColors = Theme.of(context).extension<MyColors>()!;
return Scaffold(
appBar: AppBar(
title: const Text('Flutter Theme Extensions'),
),
body: Container(
alignment: Alignment.center,
padding: const EdgeInsets.all(30),
child: Column(
children: [
Text(
'Hello Flutter',
style: Theme.of(context).textTheme.bodyLarge,
),
const SizedBox(height: 30),
Container(
width: 200,
height: 200,
color: _failure ? myColors.failure : myColors.success,
),
const SizedBox(height: 30),
TextButton(
onPressed: () {
setState(() {
_failure = !_failure;
});
},
child: Text(_failure ? 'Failure' : 'Success'),
)
],
),
),
);
}

In the above code

final myColors = Theme.of(context).extension<MyColors>()!;

helps to get the MyColors and them you can do myColors.success and myColors.failure to access our custom theme colors.

Very easy and convenient.

Watch the Video tutorial to see it in action.

Source code link

Leave a Reply

Your email address will not be published. Required fields are marked *