You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Provider跨组件使用问题:夜间模式切换无响应

问题:Provider夜间模式切换侧边栏按钮不生效

在使用Provider包实现夜间模式切换时,单独页面使用Provider可正常工作,但侧边栏的切换按钮无法生效,调试发现未进入ThemeProvider的toggleTheme()方法。

相关代码

主题类

class MyTheme {
  static ThemeData lightTheme = ThemeData(
    // 自定义浅色主题配置
  );

  static ThemeData nightTheme = ThemeData(
    // 自定义深色主题配置
  );
}

根页面

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
        create: (context) => ThemeProvider(),
        builder: (context, child) {
          final provider = Provider.of<ThemeProvider>(context);
          return MaterialApp(
            debugShowCheckedModeBanner: true,
            initialRoute: LoginScreen.id,
            onGenerateRoute: RouteGenerator.generateRoute,
            theme: provider.themeData,
            home: const HomeScreen(),
          );
        });
  }
}

首页(含侧边栏)

class _HomeScreenState extends State<HomeScreen> {
  final GlobalKey<ScaffoldState> _globalKey = GlobalKey<ScaffoldState>();

  @override
  Widget build(BuildContext context) {
    double height = MediaQuery.of(context).size.height;
    double width = MediaQuery.of(context).size.width;

    return Scaffold(
      key: _globalKey,
      drawer: MyAppDrawer(
        height: height,
        width: width,
        colore: MyTheme.coloreTesto,
      ),
      body: // 页面内容
    );
  }
}

侧边栏组件

class MyAppDrawer extends StatelessWidget {
  const MyAppDrawer(
      {super.key,
      required this.height,
      required this.width,
      required this.colore});

  final double height;
  final double width;
  final Color colore;

  @override
  Widget build(BuildContext context) {
    final provider = Provider.of<ThemeProvider>(context);

    return Drawer(
      width: width * 0.7,
      child: Container(
        padding: EdgeInsets.only(
            top: height * 0.1, left: width * 0.08, right: width * 0.08),
        color: Colors.white,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Container(
              margin: EdgeInsets.symmetric(vertical: height * 0.01),
              child: Row(
                children: [
                  Container(
                    child: ElevatedButton(
                      style: ButtonStyle(
                          backgroundColor:
                              MaterialStateProperty.all(Colors.white),
                          elevation: MaterialStateProperty.all(0.0),
                          padding: MaterialStateProperty.all(EdgeInsets.zero),
                          shape:
                              MaterialStateProperty.all<RoundedRectangleBorder>(
                                  RoundedRectangleBorder(
                                      borderRadius: BorderRadius.all(
                                          Radius.circular(width * 0.015))))),
                      onPressed: () {
                        debugPrint('nightModePremuto');
                        provider.toggleTheme; // 问题所在
                      },
                      child: Icon(
                        size: width * 0.06,
                        Icons.dark_mode,
                        color: colore,
                      ),
                    ),
                  ),
                  Text(
                    'Night Mode',
                    style: TextStyle(
                      color: colore,
                      fontSize: width * 0.04,
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Provider类

class ThemeProvider extends ChangeNotifier {
  ThemeData _themeData = MyTheme.lightTheme;
  ThemeData get themeData => _themeData;

  void toggleTheme() {
    debugPrint('Siamo entrati nel toggle');
    final isLight = _themeData == MyTheme.lightTheme;
    _themeData = isLight ? MyTheme.nightTheme : MyTheme.lightTheme;
    notifyListeners();
  }
}

解决方案

核心问题修复

你在按钮的onPressed回调中只是引用了方法对象provider.toggleTheme,并没有执行这个方法,必须添加括号才能触发方法调用:

onPressed: () {
  debugPrint('nightModePremuto');
  provider.toggleTheme(); // 添加括号执行方法
},

额外优化建议

  1. 减少不必要的组件重建:
    获取Provider时添加listen: false,因为侧边栏只需要触发主题切换,不需要监听主题变化来重建自身:

    final provider = Provider.of<ThemeProvider>(context, listen: false);
    
  2. 适配主题的背景色:
    侧边栏容器的背景色硬编码为Colors.white,切换夜间模式后不会变化,建议改成使用主题中的颜色:

    color: Theme.of(context).scaffoldBackgroundColor,
    

内容的提问来源于stack exchange,提问作者Geremia Moretti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 20:32:38