I have a Theme class that has hard coded font sizes, icon sizes, radius values, etc that I want to be dynamic so they can be responsive to different screen sizes. I haven't been able to figure out how to use MediaQuery in my Theme class because it requires a context. Is there a way to get context in my Theme class? Thanks for your help.
class MyApp extends StatelessWidget {
const MyApp({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<MenuInfoProvider>(
create: (context) => MenuInfoProvider(
MenuName.homePage,
menuIcon: Icons.home,
menuText: MenuLabelString.home,
),
),
ChangeNotifierProvider<ThemeProvider>(
create: (context) => ThemeProvider(),
),
ChangeNotifierProvider<UserProvider>(
create: (context) => UserProvider()),
Provider<Database>(
create: (context) => FirestoreDatabase(
uid: Auth().currentUser!.uid,
),
),
Provider<AuthBase>(
create: (context) => Auth(),
),
],
builder: (context, _) {
final themeProvider = Provider.of<ThemeProvider>(context);
return MaterialApp(
debugShowCheckedModeBanner: false,
title: AppConstants.improvePractice,
theme: ThemeProvider.lightTheme,
darkTheme: ThemeProvider.darkTheme,
themeMode: themeProvider.currentTheme,
initialRoute: RouteStrings.landing,
onGenerateRoute: RouteGenerator.generateRoute,
);
},
);
}
}
This is some of the code from my Theme class. The dark theme which is excluded is similar to the light theme with different colors.
class ThemeProvider extends ChangeNotifier {
ThemeMode currentTheme = ThemeMode.system;
bool get isDarkMode => currentTheme == ThemeMode.dark;
void toggleTheme({required bool isOn}) {
currentTheme = isOn ? ThemeMode.dark : ThemeMode.light;
notifyListeners();
}
static ThemeData get lightTheme {
return ThemeData(
appBarTheme: AppBarTheme(
backgroundColor: AppColors.purple,
elevation: 4.0,
iconTheme: IconThemeData(
color: AppColors.brandWhite.withOpacity(
0.87,
),
size: 24.0,
),
toolbarTextStyle: TextStyle(
color: AppColors.brandWhite.withOpacity(0.87),
fontFamily: AppTextStyle.robotoSlabFont,
fontSize: 20.0,
fontWeight: FontWeight.w500,
letterSpacing: 0.15,
),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
alignment: Alignment.center,
elevation: 2.0,
minimumSize: const Size(
64.0,
36.0,
),
onPrimary: AppColors.brandWhite.withOpacity(
0.87,
),
padding: const EdgeInsets.symmetric(
horizontal: 16.0,
vertical: 8.0,
),
primary: AppColors.purple,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
8.0,
),
),
textStyle: AppTextStyle.button,
),
),
);
}
}
CodePudding user response:
I think you could replace static ThemeData get lightTheme
by a static method that takes a BuildContext
parameter instead, Something like:
class ThemeProvider extends ChangeNotifier {
ThemeMode currentTheme = ThemeMode.system;
bool get isDarkMode => currentTheme == ThemeMode.dark;
void toggleTheme({required bool isOn}) {
currentTheme = isOn ? ThemeMode.dark : ThemeMode.light;
notifyListeners();
}
static ThemeData getLightTheme(BuildContext context) {
// Dynamic elevation depending on device Height.
final elevation = MediaQuery.of(context).size.height <600 ?4:6;
return ThemeData(
appBarTheme: AppBarTheme(
backgroundColor: AppColors.purple,
elevation: elevation,
iconTheme: IconThemeData(
color: AppColors.brandWhite.withOpacity(
0.87,
),
size: 24.0,
),
toolbarTextStyle: TextStyle(
color: AppColors.brandWhite.withOpacity(0.87),
fontFamily: AppTextStyle.robotoSlabFont,
fontSize: 20.0,
fontWeight: FontWeight.w500,
letterSpacing: 0.15,
),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
alignment: Alignment.center,
elevation: 2.0,
minimumSize: const Size(
64.0,
36.0,
),
onPrimary: AppColors.brandWhite.withOpacity(
0.87,
),
padding: const EdgeInsets.symmetric(
horizontal: 16.0,
vertical: 8.0,
),
primary: AppColors.purple,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
8.0,
),
),
textStyle: AppTextStyle.button,
),
),
);
}
}