Flutter Item ExpansionPanelList 不改变状态

Flutter Item ExpansionPanelList doesn't change state

我正在尝试从 API 检索数据,效果很好。

之后我想在 ExpansionPanelList 中显示我的数据,它是通过以下方法构建的:

class _CartaPageState extends State<CartaPage> {

  
  @override
  Widget build(BuildContext context) {
    // Nos suscribimos al provider
    final productoService = Provider.of<ProductoService>(context);
    final List<Producto> productos = productoService.productos; 
    _productosItems = productosToItem(productos);
    return Scaffold(
      body: Container(
        height: double.infinity,
        width: double.infinity,
        child: ListView(
          children: [
            ExpansionPanelList(
              animationDuration: Duration(milliseconds: 300),
              expansionCallback: (int index, bool isExpanded) {
                setState(() {
                  _productosItems[index].isExpanded = !isExpanded;
                  //productosItems[index].isExpanded = !productosItems[index].isExpanded;
                });
              },
              //children: productosToItem(productoService.entrantes).map<ExpansionPanel>((Item item) {
              children: _productosItems.map<ExpansionPanel>((Item item) {
                return ExpansionPanel(
                  headerBuilder: (context, isExpanded) {
                    return ListTile(
                      title: Text(item.headerValue),
                    );
                  },
      ................

数据显示完美,但我的 ItemModel 上的状态不是 刷新,我认为问题是因为每次我触摸面板列表时小部件都在重绘,那从 API 中(再次)检索数据并且永远不会更改状态。

我该如何解决?

提前致谢

编辑:CartaPage 由以下内容包装:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => ProductoService()),
      ],
      child: MaterialApp(
        debugShowCheckedModeBanner: false,
        title: 'Material App',
        home: CartaPage()
      ),
    );
  }
}

编辑 2:

我同意我正在丢失状态,这是将 Product 转换为 Item:

的方法
List<Item> productosToItem(List<Producto> productos) {
  return List.generate(productos.length, (index) {
    return Item(
      headerValue: productos[index].tipo,
      expandedValue: productos[index].nombre,
    );
  });
}

ExpansionPanel 是否将其 isExpanded 设置为 item.isExpanded

您可以从 productosToItem() 生成的任何内容中获得您的 isExpanded 状态。

当您调用 setState 时,您会排队一个新的构建,它将再次调用 productosToItem()。在不知道该方法的作用的情况下,我无能为力。

我建议您查看 productosToItem 以及为什么它没有将 isExpanded 设置为正确的值。

如果 _productosItems[index].isExpanded 不是 setter,我想你正在失去状态。

编辑 1:

您可以创建一个可以保留展开状态的内部状态列表:

class Item {
  Item({
    this.expandedValue,
    this.headerValue,
    this.producto,
    this.isExpanded = false,
  });

  String expandedValue;
  String headerValue;
  Producto producto; // <------------- ADDED
  bool isExpanded;
}

class _CartaPageState extends State<CartaPage> {
  Map<Producto, bool> expanded = {}; // <------------- ADDED

  @override
  Widget build(BuildContext context) {
    // Nos suscribimos al provider
    final productoService = Provider.of<ProductoService>(context);
    final List<Producto> productos = productoService.productos;
    // NOTE: ----------- converted to a local variable
    final _productosItems = productosToItem(productos);
    return Scaffold(
      body: Container(
        height: double.infinity,
        width: double.infinity,
        child: ListView(
          children: [
            ExpansionPanelList(
              key: ValueKey(productos.length),  // <------------- ADDED
              animationDuration: Duration(milliseconds: 300),
              expansionCallback: (int index, bool isExpanded) {
                // NOTE: ----------- updated
                final producto = productos[index];
                setState(() {
                  expanded[producto] = !isExpanded;
                });
              },
              children: _productosItems.map<ExpansionPanel>((Item item) {
                return ExpansionPanel(
                  isExpanded: expanded[item.producto], // <------------- ADDED
                  canTapOnHeader: true,
                  headerBuilder: (context, isExpanded) {
                    return ListTile(
                      title: Text(item.headerValue),
                    );
                  },
                  body: ListTile(
                    title: Text(item.expandedValue),
                  ),
                );
              }).toList(),
            ),
          ],
        ),
      ),
    );
  }

  List<Item> productosToItem(List<Producto> productos) {
    // keep a list of previous map
    final toRemove = Map<Producto, bool>.from(expanded);
    final items = List.generate(productos.length, (index) {
      final producto = productos[index];
      // set initial expanded state
      expanded.putIfAbsent(producto, () => false);
      // the item will be retained
      toRemove.remove(producto);
      return Item(
        headerValue: producto.tipo,
        expandedValue: producto.nombre,
        producto: producto,
        isExpanded: expanded[producto],
      );
    });
    if (toRemove.isNotEmpty) {
      // cleanup unused items
      expanded.removeWhere((key, _) => toRemove.containsKey(key));
    }
    return items;
  }
}

key: ValueKey(productos.length), 是必需的,因为 ExpansionPanelList 对神奇地出现或消失的物品表现得很奇怪。