如何在没有 Build 方法的情况下获取小部件中的上下文
How to get the context in a widget without a Build method
我有一个主题 class,它具有硬编码的字体大小、图标大小、半径值等,我希望它们是动态的,以便它们可以响应不同的屏幕尺寸。我一直无法弄清楚如何在我的主题 class 中使用 MediaQuery,因为它需要上下文。有没有办法在我的主题 class 中获取上下文?感谢您的帮助。
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,
);
},
);
}
}
这是我的主题 class 中的一些代码。被排除的深色主题与浅色主题相似,颜色不同。
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,
),
),
);
}
}
我认为您可以将 static ThemeData get lightTheme
替换为采用 BuildContext
参数的静态方法,例如:
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,
),
),
);
}
}
我有一个主题 class,它具有硬编码的字体大小、图标大小、半径值等,我希望它们是动态的,以便它们可以响应不同的屏幕尺寸。我一直无法弄清楚如何在我的主题 class 中使用 MediaQuery,因为它需要上下文。有没有办法在我的主题 class 中获取上下文?感谢您的帮助。
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,
);
},
);
}
}
这是我的主题 class 中的一些代码。被排除的深色主题与浅色主题相似,颜色不同。
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,
),
),
);
}
}
我认为您可以将 static ThemeData get lightTheme
替换为采用 BuildContext
参数的静态方法,例如:
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,
),
),
);
}
}