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

Navigator.push不在作用域时,如何调用setState刷新页面?

解决从SettingsScreen返回后刷新MainScreen的问题

你的核心问题是:自定义AppBar里无法直接调用MainScreen的setState,因为两者属于不同的类。下面给你两种简单可行的解决方案:

方案一:给PlantAppBar添加返回回调

通过给自定义AppBar传入一个回调函数,当从SettingsScreen返回时触发这个回调,让MainScreen自己处理刷新逻辑。

步骤1:修改PlantAppBar代码

添加回调参数,并在跳转返回后执行回调:

class PlantAppBar extends StatelessWidget implements PreferredSizeWidget {
  @override
  final Size preferredSize = Size.fromHeight(50);
  final String title = 'Pflanzen';
  final bool showSettingsButton;
  final VoidCallback? onSettingsReturn; // 新增返回回调参数

  PlantAppBar(this.showSettingsButton, {this.onSettingsReturn, super.key});

  @override
  Widget build(BuildContext context) {
    return AppBar(
      actions: [if(showSettingsButton) settingsButton(context)], // 修正原代码的语法错误
      automaticallyImplyLeading: false,
      title: Text(title, style: TextStyle(color: Theme.of(context).colorScheme.onPrimary)),
      backgroundColor: Theme.of(context).colorScheme.primary,
      toolbarTextStyle: TextStyle(color: Theme.of(context).colorScheme.onPrimary),
    );
  }

  Widget settingsButton(context){
    return IconButton(
      onPressed: (){navigateToSettings(context);}, 
      icon: Icon(Icons.more_vert, color: Theme.of(context).colorScheme.onPrimary,)
    );
  }

  void navigateToSettings(context){
    Navigator.push(
      context, 
      MaterialPageRoute(builder: (context) => Settingsscreen()),
    ).then((_) {
      // 返回后执行回调
      onSettingsReturn?.call();
    });
  }
}

步骤2:在MainScreen中传入回调

创建PlantAppBar时,传入刷新逻辑的回调:

@override
Widget build(BuildContext context){
  return Scaffold(
    appBar: PlantAppBar(
      true,
      onSettingsReturn: () {
        // 重新获取数据,触发StreamBuilder更新UI
        setState(() {
          mainVM.fetchPlants();
        });
      },
    ),
    backgroundColor: Theme.of(context).colorScheme.surface,
    body: StreamBuilder<List<Plant>>(
        stream: mainVM.plantStream,
        builder: (context, snapshot) {
          if (snapshot.hasError){
            return Text("Error: ${snapshot.error}", style: TextStyle(color: Colors.red));
          }else if (snapshot.hasData){
            plants = snapshot.data!;
            return _buildListView();
          }else{
            return Center(child: Text("Nutze den (+) Button um deine erste Pflanze anzulegen"));
          }
        }),
  );
}

方案二:把跳转逻辑移到MainScreen中

让AppBar的按钮只负责触发MainScreen里的跳转方法,这样就能直接在MainScreen的State中处理返回后的刷新。

步骤1:修改PlantAppBar代码

将跳转逻辑替换为回调,让MainScreen处理:

class PlantAppBar extends StatelessWidget implements PreferredSizeWidget {
  @override
  final Size preferredSize = Size.fromHeight(50);
  final String title = 'Pflanzen';
  final bool showSettingsButton;
  final VoidCallback? onSettingsPressed; // 新增点击回调

  PlantAppBar(this.showSettingsButton, {this.onSettingsPressed, super.key});

  @override
  Widget build(BuildContext context) {
    return AppBar(
      actions: [if(showSettingsButton) settingsButton(context)],
      automaticallyImplyLeading: false,
      title: Text(title, style: TextStyle(color: Theme.of(context).colorScheme.onPrimary)),
      backgroundColor: Theme.of(context).colorScheme.primary,
      toolbarTextStyle: TextStyle(color: Theme.of(context).colorScheme.onPrimary),
    );
  }

  Widget settingsButton(context){
    return IconButton(
      onPressed: onSettingsPressed, // 直接触发传入的回调
      icon: Icon(Icons.more_vert, color: Theme.of(context).colorScheme.onPrimary,)
    );
  }
}

步骤2:在MainScreen中处理跳转和刷新

@override
Widget build(BuildContext context){
  return Scaffold(
    appBar: PlantAppBar(
      true,
      onSettingsPressed: () async {
        // 等待从SettingsScreen返回
        await Navigator.push(
          context, 
          MaterialPageRoute(builder: (context) => Settingsscreen()),
        );
        // 返回后刷新数据
        setState(() {
          mainVM.fetchPlants();
        });
      },
    ),
    backgroundColor: Theme.of(context).colorScheme.surface,
    body: StreamBuilder<List<Plant>>(
        stream: mainVM.plantStream,
        builder: (context, snapshot) {
          if (snapshot.hasError){
            return Text("Error: ${snapshot.error}", style: TextStyle(color: Colors.red));
          }else if (snapshot.hasData){
            plants = snapshot.data!;
            return _buildListView();
          }else{
            return Center(child: Text("Nutze den (+) Button um deine erste Pflanze anzulegen"));
          }
        }),
  );
}

补充说明

两种方案本质都是把刷新逻辑交回给MainScreen的State类,因为只有State类能调用setState。另外你的UI是通过StreamBuilder构建的,只要mainVM.fetchPlants()更新了plantStream,StreamBuilder就会自动重建UI,所以setState在这里主要是确保Widget状态更新,核心还是重新获取数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.01 13:24:54