Last active
June 28, 2022 17:14
-
-
Save SuperPenguin/3ecf0aa4eea05cdef9f3a76e4c411c80 to your computer and use it in GitHub Desktop.
ThemeExtension example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
Future<void> main() async { | |
WidgetsFlutterBinding.ensureInitialized(); | |
runApp(const App()); | |
} | |
class App extends StatefulWidget { | |
const App({Key? key}) : super(key: key); | |
@override | |
State<App> createState() => AppState(); | |
static AppState of(BuildContext context) { | |
return context.findAncestorStateOfType<AppState>()!; | |
} | |
} | |
class AppState extends State<App> { | |
ThemeMode _themeMode = ThemeMode.light; | |
void setThemeMode(ThemeMode themeMode) { | |
if (_themeMode != themeMode) { | |
setState(() { | |
_themeMode = themeMode; | |
}); | |
} | |
} | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
title: 'Desktop App', | |
themeMode: _themeMode, | |
theme: ThemeData( | |
brightness: Brightness.light, | |
extensions: { | |
// or you can make | |
// PenguinThemeData( | |
// backColor: ..., | |
// bellyColor: ..., | |
// ), | |
PenguinThemeData.defaultLight, | |
}, | |
), | |
darkTheme: ThemeData( | |
brightness: Brightness.dark, | |
extensions: { | |
PenguinThemeData.defaultDark, | |
}, | |
), | |
home: const HomePage(), | |
); | |
} | |
} | |
class Penguin extends StatelessWidget { | |
const Penguin({Key? key}) : super(key: key); | |
@override | |
Widget build(BuildContext context) { | |
final penguinTheme = PenguinThemeData.of(context); | |
return Row( | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
Card( | |
color: penguinTheme.backColor, | |
child: Padding( | |
padding: const EdgeInsets.all(8.0), | |
child: Text( | |
'Back', | |
style: TextStyle( | |
color: ThemeData.estimateBrightnessForColor( | |
penguinTheme.backColor) == | |
Brightness.light | |
? Colors.black | |
: Colors.white, | |
), | |
), | |
), | |
), | |
Card( | |
color: penguinTheme.bellyColor, | |
child: Padding( | |
padding: const EdgeInsets.all(8.0), | |
child: Text( | |
'Belly', | |
style: TextStyle( | |
color: ThemeData.estimateBrightnessForColor( | |
penguinTheme.bellyColor) == | |
Brightness.light | |
? Colors.black | |
: Colors.white, | |
), | |
), | |
), | |
), | |
], | |
); | |
} | |
} | |
@immutable | |
class PenguinThemeData extends ThemeExtension<PenguinThemeData> { | |
const PenguinThemeData({ | |
required this.backColor, | |
required this.bellyColor, | |
}); | |
final Color backColor; | |
final Color bellyColor; | |
static const defaultLight = PenguinThemeData( | |
backColor: Colors.grey, | |
bellyColor: Colors.white, | |
); | |
static const defaultDark = PenguinThemeData( | |
backColor: Colors.black, | |
bellyColor: Colors.grey, | |
); | |
static PenguinThemeData of(BuildContext context) { | |
final theme = Theme.of(context); | |
final penguinTheme = | |
theme.extensions[PenguinThemeData] as PenguinThemeData?; | |
if (penguinTheme != null) { | |
return penguinTheme; | |
} | |
return theme.brightness == Brightness.light ? defaultLight : defaultDark; | |
} | |
@override | |
ThemeExtension<PenguinThemeData> copyWith({ | |
Color? backColor, | |
Color? bellyColor, | |
}) { | |
return PenguinThemeData( | |
backColor: backColor ?? this.backColor, | |
bellyColor: bellyColor ?? this.bellyColor, | |
); | |
} | |
@override | |
ThemeExtension<PenguinThemeData> lerp( | |
ThemeExtension<PenguinThemeData>? other, | |
double t, | |
) { | |
if (other is! PenguinThemeData) return this; | |
return PenguinThemeData( | |
backColor: Color.lerp(backColor, other.backColor, t)!, | |
bellyColor: Color.lerp(bellyColor, other.bellyColor, t)!, | |
); | |
} | |
@override | |
bool operator ==(Object other) { | |
if (identical(this, other)) return true; | |
return other is PenguinThemeData && | |
other.backColor == backColor && | |
other.bellyColor == bellyColor; | |
} | |
@override | |
int get hashCode { | |
return Object.hashAll([ | |
backColor, | |
bellyColor, | |
]); | |
} | |
} | |
class HomePage extends StatefulWidget { | |
const HomePage({Key? key}) : super(key: key); | |
@override | |
State<HomePage> createState() => _HomePageState(); | |
} | |
class _HomePageState extends State<HomePage> { | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
title: const Text('AppBar'), | |
), | |
body: Center( | |
child: Column( | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
const Penguin(), | |
Row( | |
mainAxisSize: MainAxisSize.min, | |
children: [ | |
TextButton( | |
onPressed: () => App.of(context).setThemeMode( | |
ThemeMode.light, | |
), | |
child: const Text('Light'), | |
), | |
TextButton( | |
onPressed: () => App.of(context).setThemeMode( | |
ThemeMode.dark, | |
), | |
child: const Text('Dark'), | |
), | |
], | |
), | |
], | |
), | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment