flutter - List.remove() 删除了正确的对象,但列表中对象的状态发生了变化,就好像最后一个条目正在被删除一样

标签 flutter dart flutter-state

所以我已经尝试解决这个问题几天了,我似乎在这里遇到了真正的死胡同。
问题(我在下面的代码中已简化)是当我尝试从 List<"SomeDataObject"> 中删除项目时,它实际上从列表中删除了正确的对象。这很明显,因为我任意分配给对象的 ID 确实会发生变化,正如我在删除某些内容时所期望的那样。然而,奇怪的是,即使 ID 在列表中移动并删除了正确的 ID,所有小部件的状态似乎总是删除最后一个项目,即使删除的对象位于中间甚至开头的名单。
一个例子是,如果列表看起来像这样:

Data(id: 630) // This one starts blue
Data(id: 243) // Let's say the user made this one red
Data(id: 944) // Also blue
假设我试图从这个列表中删除中间项目。好吧,列表现在看起来像这样:
Data(id: 630)
Data(id: 944)
起初这似乎很棒,因为它看起来正是我想要的,但出于某种原因,颜色没有改变它们的顺序,仍然是先红色,然后是蓝色。颜色状态数据似乎独立于实际对象运行,我找不到明确的解决方案。
我有一个示例程序的代码来重现这个问题,我还在程序下面放了一些图片,以便更清楚地说明问题是什么。
import 'dart:math';

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: HomeScreen(),
    );
  }
}

// Home screen class to display app
class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  List<DataWidget> widgetsList = List<DataWidget>();

  // Adds a new data object to the widgets list
  void addData() {
    setState(() {
      widgetsList.add(DataWidget(removeData));
    });
  }

  // Removes a given widget from the widgets list
  void removeData(DataWidget toRemove) {
    setState(() {
      widgetsList = List.from(widgetsList)..remove(toRemove);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      /* I used a SingleChildScrollView instead of ListView because ListView
      resets an objects state when it gets out of view so I wrapped the whole
      list in a column and then passed that to the SingleChildScrollView to
      force it to stay in memory. It is worth noting that this problem still
      exists even when using a regular ListView. */
      body: SingleChildScrollView(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          // Added a SizedBox just to make column take up whole screen width
          children: [...widgetsList, SizedBox(width: double.infinity)],
        ),
      ),
      // FloatingActionButton just to run addData function for example
      floatingActionButton: FloatingActionButton(onPressed: addData),
    );
  }
}

// Simple class that is a red square that when clicked turns blue when pressed
class DataWidget extends StatefulWidget {
  DataWidget(this.onDoubleTap);
  final Function(DataWidget) onDoubleTap;

  // Just a random number to keep track of which widget this is
  final String id = Random.secure().nextInt(1000).toString();

  @override
  String toStringShort() {
    return id;
  }

  @override
  _DataWidgetState createState() => _DataWidgetState();
}

class _DataWidgetState extends State<DataWidget> {
  /* Here the example state information is just a color, but in the full version
  of this problem this actually has multiple fields */
  Color color = Colors.red;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: GestureDetector(
        // onDoubleTap this passes itself to the delete method of the parent
        onDoubleTap: () => widget.onDoubleTap(widget),
        // Changes color on tap to whatever color it isn't
        onTap: () {
          setState(() {
            color = color == Colors.red ? Colors.blue : Colors.red;
          });
        },
        child: Container(
          child: Center(child: Text(widget.id)),
          width: 200,
          height: 200,
          color: color,
        ),
      ),
    );
  }
}

在用户更改任何颜色之前(对象 ID 在容器上显示为文本):
1
用户通过点击将中间容器更改为蓝色:
2
用户尝试通过双击删除中间(蓝色)容器:
enter image description here
从上图可以看出,ID 被删除,下方的 ID 在屏幕上向上移动,但状态中的颜色信息并没有被删除。
任何尝试的想法将不胜感激。

最佳答案

您需要对您的 DataWidget 进行一些更改类使其工作:

// Simple class that is a red square that when clicked turns blue when pressed
class DataWidget extends StatefulWidget {

  Color color = Colors.red; // moved from _DataWidgetState class

  DataWidget(this.onDoubleTap);
  final Function(DataWidget) onDoubleTap;

  // Just a random number to keep track of which widget this is
  final String id = Random.secure().nextInt(1000).toString();

  @override
  String toStringShort() {
    return id;
  }

  @override
  _DataWidgetState createState() => _DataWidgetState();
}

class _DataWidgetState extends State<DataWidget> {
  /* Here the example state information is just a color, but in the full version
  of this problem this actually has multiple fields */

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: GestureDetector(
        // onDoubleTap this passes itself to the delete method of the parent
        onDoubleTap: () => widget.onDoubleTap(widget),
        // Changes color on tap to whatever color it isn't
        onTap: () {
          setState(() {
            widget.color =
                widget.color == Colors.red ? Colors.blue : Colors.red;
          });
        },
        child: Container(
          child: Center(child: Text(widget.id)),
          width: 200,
          height: 200,
          color: widget.color,
        ),
      ),
    );
  }
}

关于flutter - List.remove() 删除了正确的对象,但列表中对象的状态发生了变化,就好像最后一个条目正在被删除一样,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63627430/

相关文章:

dart - Flutter 在真机上运行报错

flutter - 从 Flutter 图像中的 Png 中删除白色背景

flutter - Flutter中返回错误 "The body might complete normally, causing ' null',但返回类型为“

flutter - 如何在不使用任何库的情况下在flutter中使用bloc

整个应用程序的 Flutter 集中/通用加载屏幕

flutter - 在 Flutter 中声明样式文件

flutter - flutter sendMessage() 中的 Firebase 消息传递

flutter - 非常简单的图像在 Flutter 中加载速度很慢

mobile - 在 Windows 上运行 Flutter

flutter 底部导航栏不切换屏幕