Challenge 4
- Flutter course
- Expert
- Lesson 39/39
- 3 min
Build a multi-theme design system with tokens and ThemeExtension.
Multi-theme with tokens and ThemeExtension
Tokens gather design values in one place; ThemeExtension adds these values as custom fields in ThemeData. You define separate token sets for light and dark themes, registering each with a distinct AppColors extension. The extensions parameter attaches the extension to ThemeData.
class AppTokens {
static const Color lightBrand = Color(0xFF1A73E8);
static const Color darkBrand = Color(0xFF66A8FF);
}
ThemeData lightTheme = ThemeData(
extensions: [const AppColors(brand: AppTokens.lightBrand)],
);Practice Write tokens and AppColors
Define two Color constants lightBrand (0xFF1A73E8) and darkBrand (0xFF66A8FF) in an AppTokens class. Write a ThemeExtension subclass named AppColors with a brand field, copyWith and lerp methods. In main create an AppColors with lightBrand and print brand.
Starter code
import 'package:flutter/material.dart';
// AppTokens: iki marka rengi sabiti
// AppColors: ThemeExtension tabanlı, brand alanı
// Kopyalama ve ara değer metodlarını uygula
// main: AppColors oluştur ve brand yazdır
void main() {
}Sample solution
import 'package:flutter/material.dart';
class AppTokens {
static const Color lightBrand = Color(0xFF1A73E8);
static const Color darkBrand = Color(0xFF66A8FF);
}
class AppColors extends ThemeExtension<AppColors> {
final Color brand;
const AppColors({required this.brand});
@override
AppColors copyWith({Color? brand}) =>
AppColors(brand: brand ?? this.brand);
@override
AppColors lerp(AppColors? other, double t) =>
AppColors(brand: Color.lerp(brand, other?.brand, t)!);
}
void main() {
final colors = const AppColors(brand: AppTokens.lightBrand);
print(colors.brand);
}Expected output
Color(0xff1a73e8)
Practice Light and dark themes
Write the same AppTokens and AppColors classes. In main create two AppColors instances: one with lightBrand and one with darkBrand. Print each one's brand color on a separate line.
Starter code
import 'package:flutter/material.dart';
// AppTokens: açık ve koyu marka renkleri
// AppColors: ThemeExtension, brand alanı
// Kopyalama ve ara değer metodlarını uygula
// main: hem açık hem koyu AppColors oluştur
// Her ikisinin brand rengini yazdır
void main() {
}Sample solution
import 'package:flutter/material.dart';
class AppTokens {
static const Color lightBrand = Color(0xFF1A73E8);
static const Color darkBrand = Color(0xFF66A8FF);
}
class AppColors extends ThemeExtension<AppColors> {
final Color brand;
const AppColors({required this.brand});
@override
AppColors copyWith({Color? brand}) =>
AppColors(brand: brand ?? this.brand);
@override
AppColors lerp(AppColors? other, double t) =>
AppColors(brand: Color.lerp(brand, other?.brand, t)!);
}
void main() {
final light = const AppColors(brand: AppTokens.lightBrand);
final dark = const AppColors(brand: AppTokens.darkBrand);
print(light.brand);
print(dark.brand);
}Expected output
Color(0xff1a73e8) Color(0xff66a8ff)
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 How is a ThemeExtension added to a ThemeData?
- Embedded into colorScheme
- Via the extensions parameter Correct answer
- With setExtension in main
- Via the theme parameter
Explanation: ThemeData's extensions parameter takes a list; ThemeExtension instances are listed there.
2 extensions parameter
ThemeData(
____: [const AppColors(brand: AppTokens.lightBrand)],
);
ThemeData(
extensions: [const AppColors(brand: AppTokens.lightBrand)],
);
Explanation: The extensions parameter registers ThemeExtension instances in ThemeData; descendants access them via Theme.of(context).
3 Multi-theme system parts
| Term | Meaning |
|---|---|
AppTokens |
Design value constants |
ThemeExtension |
Custom theme field |
extensions |
Extension registration in ThemeData |
lerp |
Interpolation between themes |