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

Flutter中PopupMenuItem关闭后如何更新界面UI

问题根本原因

  1. DataTableSource 变更数据源后必须主动调用 notifyListeners() 才能通知表格刷新,你之前删除操作只调用了后端接口,没有触发这个通知。
  2. 你定义的 _resultData 是 final 不可修改类型,后端删除成功后本地缓存的列表数据完全没更新,表格渲染用的还是旧数据。
  3. 上层有状态Widget没有监听删除成功的事件,也没有调用setState触发重绘,PaginatedDataTable不会自动重建。
  4. 额外优化点:每个行的DataCell里嵌套FutureBuilder重复拉取品牌列表属于冗余逻辑,完全没必要,父组件已经拿到全量数据可以直接用。

具体修改步骤

1. 修改ResultDataSource类

class ResultDataSource extends  DataTableSource{
  var brandsController = BrandsController(BrandsRepository());
  ResultDataSource({
    @required List<Result> resultData,
    @required this.onRowSelect,
    // 新增删除成功回调
    @required this.onDeleteSuccess,
  })  : _resultData = resultData,
        assert(resultData != null);

  // 去掉final,允许修改数据源
  List<Result> _resultData;
  final OnRowSelect onRowSelect;
  final Function(int deletedIndex) onDeleteSuccess;

  // 新增删除本地数据并刷新表格的方法
  void deleteItem(int index) {
    _resultData.removeAt(index);
    // 必须调用这个方法通知DataTable刷新
    notifyListeners();
  }

  @override
  DataRow getRow(int index) {
    assert(index >= 0);

    if (index >= _resultData.length) {
      return null;
    }
    final _result = _resultData[index];

    return DataRow.byIndex(
      index: index,
      cells: <DataCell>[
        DataCell(Text('${_result.name}',style: TextStyle(fontSize: 13.0, fontWeight: FontWeight.w600, color: secondaryColor))),
        DataCell(Text('${_result.country}',style: TextStyle(fontSize: 13.0, color: secondaryColor))),
        DataCell(Text('${_result.isActive.toString() == "true" ? "Active" : "Inactive"}',style: TextStyle(fontSize: 13.0, fontWeight: FontWeight.w500, color: primaryColor),)),
        DataCell(
          // 删掉冗余的FutureBuilder,不需要每行都拉取品牌列表
          PopupMenuButton(
            elevation: 20.0,
            icon: Icon(
              Icons.more_horiz,
              color: secondaryColor.withOpacity(0.5),
            ),
            itemBuilder: (context) =>[
              // 其他菜单项逻辑保持不变,仅修改删除项的onTap逻辑
              PopupMenuItem(
                // 改成异步等待接口返回成功
                onTap: () async {
                  await brandsController.deleteBrand(_result.id.toString());
                  // 先更新数据源自身的列表,通知表格刷新
                  deleteItem(index);
                  // 回调上层父组件,同步更新父级的数据源
                  onDeleteSuccess(index);
                },
                child:Row(
                  children: [
                    SvgPicture.asset("assets/icons/garbage.svg", height: 18.0,color: Colors.blueGrey, ),
                    SizedBox(width:10.0),
                    Text("Delete", style: TextStyle(color: Colors.blueGrey, fontSize: 13.0),)
                  ],
                ),
                value: 4,
              ),
            ],
          )
        ),
      ],
    );
  }
  // 剩余原有方法保持不变
  @override
  bool get isRowCountApproximate => false;
  @override
  int get rowCount => _resultData.length;
  @override
  int get selectedRowCount => 0;
}

2. 修改上层有状态Widget代码

首先在State类中定义本地存储的品牌列表:

class _YourWidgetState extends State<YourWidget> {
  List<Result> _currentBrandList;
  // 其他原有逻辑保持不变

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<List<Result>>(
      // 把原来每个cell里的拉取逻辑移到父组件这里,全局只拉取一次
      future: brandsController.fetchBrandList(),
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          // 接口返回后给本地列表赋值
          _currentBrandList = snapshot.data;
          return ListView(
            padding: const EdgeInsets.all(16),
            shrinkWrap: true,
            children: [
              Theme(
                data: Theme.of(context).copyWith(
                  dividerColor: Colors.blueGrey.shade100.withOpacity(0.4),
                ),
                child: PaginatedDataTable(
                  rowsPerPage: _currentBrandList.length ?? 1,
                  showCheckboxColumn: true,
                  dataRowHeight: 60,
                  columns: [
                    // 列定义保持原有逻辑不变,此处省略
                  ],
                  source: ResultDataSource(
                    onRowSelect: (index) => () {},
                    resultData: _currentBrandList,
                    // 实现删除成功的回调,更新父组件状态触发重绘
                    onDeleteSuccess: (deletedIndex) {
                      setState(() {
                        _currentBrandList.removeAt(deletedIndex);
                      });
                    },
                  ),
                ),
              ),
            ],
          );
        }
        // 其他加载、错误状态逻辑保持不变
        return const CircularProgressIndicator();
      },
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 19:54:04