Flutter 提供程序无法与动态构建的 ExpansionPanelRadio 一起使用

Flutter provider not working with dynamically built ExpansionPanelRadio

提问人:Alec Stanley 提问时间:10/4/2023 最后编辑:Alec Stanley 更新时间:10/5/2023 访问量:20

问:

我正在构建一个应用程序,其中 ExpansionPanelList 是从自定义类动态构建的。该列表位于标题下方,其中包含有关列表内容的一些详细信息,包括项目总数。

当使用每个单选面板上的尾部按钮从列表中删除项目时,项目将从列表中删除,但标题中显示的总数不会更改(除非用户更改页面并再次返回,从而强制重新生成)。提供程序在封装静态构建的小部件时似乎工作得很好,但这个动态小部件给它带来了问题。我最初使用无状态小部件,但这样做意味着每个面板上的滑块不会更新,列表也不会重新构建,直到采取一些措施来强制它。

我更改为无状态,解决了该问题,但标题未刷新仍然存在。

编辑:这里有一个小总结:

Consumer+builder    
  ->Tab
    -> Header,
    -> Builder[ExpandingPanels…]
  ->Drawer

我有消费者的根源,一直尝试到树下,但没有效果。Child 属性设置为“_”,以便它不会忽略 children。

在标题和每个展开面板上,我都添加了一个删除按钮,用于从生成展开面板的列表中删除一个项目。

在抽屉上,我添加了一个按钮,用于将项目添加到列表中。

当按下删除(在页眉和面板上)或添加(在抽屉上)时,结果如下:

  • 无状态/有状态标头 - >列表重建、标头更新(即全部按预期工作)
  • 有状态列表 -> 列表重新生成,标头不更新
  • 有状态抽屉>既不更新列表也不更新标头

所以看起来兄弟姐妹正在和每个人说话

这是标头代码,您可以看到 2 个使用者(除非来回移动到此页面,否则它们不会更新。

class BagHeaderBar extends StatelessWidget {
  const BagHeaderBar({
    Key? key,
    required this.bagIndex,
  }) : super(key: key);

  final int bagIndex;

  @override
  Widget build(BuildContext context) {
    return Card(
        child: Padding(
          child: IntrinsicHeight(
            child: Row(
              children: <Widget>[
                Expanded(
                    flex: 8,
                    child: Align(
                      alignment: Alignment.centerLeft,
                      child: Consumer<PlayerCharacter>(   // <--------- this doesn't seem to 'consume'
                          builder: (context, player, _) {
                        return Text(
                          player.bag[bagIndex].bagNotes,
                        );
                      }),
                    )),
                Expanded(
                  flex: 2,
                  child: Align(
                    alignment: Alignment.centerRight,
                    child: Consumer<PlayerCharacter>(     // <--------- this doesn't seem to 'consume'
                        builder: (context, player, _) {
                      return Text(
                        '${player.bag[bagIndex].capacityUsed} / ${player.bag[bagIndex].capacityMax}',
                        style: const TextStyle(fontSize: 18),
                      );
                    }),
                  ),
                ),
              ],
            ),
          ),
        ));
  }
}

这是动态构建的代码,它有删除按钮。它们旨在从列表中删除项目并调整标题中的数字。该项目将被删除(因为它现在是有状态的。它在无状态时不会刷新,但数据已从对象中删除。


class ExpansionInventoryBag extends StatefulWidget {
  const ExpansionInventoryBag({
    Key? key,
    required this.bagIndex,
  }) : super(key: key);

  final int bagIndex;

  @override
  State<ExpansionInventoryBag> createState() => _ExpansionInventoryBagState();
}
//---------------------------------------------
class _ExpansionInventoryBagState extends State<ExpansionInventoryBag> {
  @override
  Widget build(BuildContext context) {

    final player = context.read<PlayerCharacter>();

    return SingleChildScrollView(
        child: ExpansionPanelList.radio(
          children: player.bag[widget.bagIndex].contents!.map<ExpansionPanelRadio>((BagSlot bagSlot) {
            return ExpansionPanelRadio(
                canTapOnHeader: true,
                value: bagSlot.slotId,
                headerBuilder: (BuildContext context, bool isExpanded) {
                  return ListTile(
                    title: Text(
                        '${bagSlot.getBaseInventoryItem().name} ${(bagSlot.quantity > 1) ? "(${bagSlot.quantity})" : ""}'),
                    trailing: bagSlot.getBaseInventoryItem().equippable
                        ? Switch(
                            value: bagSlot.equipped,
                            onChanged: (bool value) {
                              final player = context.read<PlayerCharacter>();
                              setState(() { 
                                player.bag[widget.bagIndex]
                                    .setEquipStateById(bagSlot.slotId, value);
                              });
                            },
                          )
                        : null,
                  );
                },
                body: ListTile(
                  title: Text(bagSlot.getBaseInventoryItem().shortDescription),
                  subtitle: Text(bagSlot.slotId),
                  trailing: const Icon(Icons.delete),
                  onTap: () {
                    setState(() {
                      player.bag[widget.bagIndex].removeItemById(bagSlot.slotId);
                    });
                    //final player = context.read<PlayerCharacter>();
                  },
                ));
          }).toList(),
        ),
      );

  }
}


我尝试动态生成 ChangeNotiferProviders,为 BagSlot(构成面板的元素)生成多个提供程序。无状态和有状态小部件。回调。

提供 flutter-change-notifier

评论


答: 暂无答案