ReorderableListView 中的 Flutter Checkbox 错误动画

Flutter Checkbox wrong animation inside a ReorderableListView

我一定是做错了什么,但是当我在 ReorderableListView 中重新排序选中的复选框时,它正在为未选中的图块设置动画:

这是我正在使用的示例代码:

ReorderableListView(
  padding: const EdgeInsets.symmetric(horizontal: 40),
  children: <Widget>[
    for (int index = 0; index < _items.length; index++)
      ListTile(
        leading: Checkbox(
          
          key: Key('$index'),
          onChanged: (v) => null,
          value: _items[index].isOdd ? true : false,
        ),
        key: Key('$index'),
        tileColor: _items[index].isOdd ? oddItemColor : evenItemColor,
        title: Text('Item ${_items[index]}'),
      ),
  ],
  onReorder: (int oldIndex, int newIndex) {
    setState(() {
      if (oldIndex < newIndex) {
        newIndex -= 1;
      }
      final int item = _items.removeAt(oldIndex);
      _items.insert(newIndex, item);
    });

完整 code here!

我怎样才能正确地做到这一点? 干杯!

我刚刚意识到我的错误,使用 key: Key('$index') 是错误的,因为它正在更改 onReorder,所以 flutter 正在将我的旧选中 Checkbox 值与新的未选中 Checkbox(我的错误 =| ).只需在 ListTile 中使用 ObjectKey 即可正确匹配!

ListTile(
        leading: Checkbox(
          onChanged: (v) => null,
          value: _items[index].isOdd ? true : false,
        ),
        key: ObjectKey(_items[index]),
        tileColor: _items[index].isOdd ? oddItemColor : evenItemColor,
        title: Text('Item ${_items[index]}'),
      ),

首先,您只需要 ListTile 上的密钥,因为它们是 ReorderableListView.

的直系后代

其次,key需要非index-based。您可以使用 UniqueKeyGlobalKey,但最佳做法是使用 ValueKey,传递该索引处的值。

你的情况:

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  final List<int> _items = List<int>.generate(2, (int index) => index);

  @override
  Widget build(BuildContext context) {
    return ReorderableListView(
      padding: const EdgeInsets.symmetric(horizontal: 40),
      children: <Widget>[
        for (int index = 0; index < _items.length; index++)
          ListTile(
            leading: Checkbox(
              onChanged: (v) => null,
              value: _items[index].isOdd ? true : false,
            ),
            // here
            key: ValueKey(_items[index]),
            tileColor: _items[index].isOdd ? oddItemColor : evenItemColor,
            title: Text('Item ${_items[index]}'),
          ),
      ],
      onReorder: (int oldIndex, int newIndex) {
        setState(() {
          if (oldIndex < newIndex) {
            newIndex -= 1;
          }
          final int item = _items.removeAt(oldIndex);
          _items.insert(newIndex, item);
        });
      },
    );
  }
}

至于为什么您的索引键不起作用 - 我的理解是,在小部件重建后(从重新排序列表),您的 ListTile 键控在错误的索引处(因为那个 ListTile 已更改)。当您使用该值时,它是一个常量,可用于识别小部件。

Medium 上的 Emily Fortuna 写了一篇 wonderful article 关于按键的文章,如果您打算继续使用 Flutter 进行开发,我强烈建议您阅读这篇文章。