4

所以我这几天一直在尝试解决这个问题,我似乎在这里遇到了一个真正的死胡同。

问题(我在下面的代码中简化了)是当我尝试从 a 中删除一个项目时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

用户尝试通过双击删除中间(蓝色)容器: 在此处输入图像描述

从上图可以看出,ID被删除了,下面的ID在屏幕上向上移动了,但是状态中的颜色信息并没有被删除。

任何尝试的想法将不胜感激。

4

1 回答 1

3

您需要对您的课程进行一些更改才能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,
        ),
      ),
    );
  }
}
于 2020-08-28T05:20:52.637 回答