如何在没有 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,
        ),
      ),
    );
  }
}