CheckBox 动画在 ReorderableListView 内时不起作用

Posted

技术标签:

【中文标题】CheckBox 动画在 ReorderableListView 内时不起作用【英文标题】:CheckBox animation doesn't work when inside a ReorderableListView 【发布时间】:2020-05-31 04:17:39 【问题描述】:

我正在尝试制作一个简单的任务列表,其中包含文本和一个复选框,并允许您重新排序任务。重新排序的所有逻辑都在工作,但是在选择任务时复选框更新而不运行动画。

我遇到了一个类似于简单列表 (ListView) 的问题,通过放置一个 ObjectKey 问题得到了解决。在这个例子中,如你所见,还有一个 Key,但动画不起作用。有什么建议吗?

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
      title: 'Flutter To Do',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: HomePage(),
    ));

class HomePage extends StatefulWidget 
  @override
  _HomePageState createState() => _HomePageState();


class _HomePageState extends State<HomePage> 
  List myItems = [];

  @override
  void initState() 
    super.initState();
    for (int i = 0; i < 10; i++) 
      Map<String, dynamic> newTask = Map();
      newTask['task'] = 'Task #$i';
      newTask['done'] = false;
      myItems.add(newTask);
    
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
        appBar: AppBar(
          title: Text('Flutter To Do'),
        ),
        body: ReorderableListView(
          children: [
            for (final item in myItems)
              Card(
                key: ObjectKey(item),
                margin: EdgeInsets.all(0),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(0)
                ),
                child: Container(
                  height: 56,
                  child: Row(
                    children: <Widget>[
                      IconButton(icon: Icon(Icons.reorder), onPressed: null),
                      Expanded(
                        child: Text(item['task']),
                      ),
                      Checkbox(
                        value: item['done'],
                        onChanged: (value) 
                          setState(() 
                            item['done'] = value;
                          );
                        ,
                      )
                    ],
                  ),
                ),
              )
          ],
          onReorder: (oldIndex, newIndex) 
            setState(() 
              if (newIndex > oldIndex) 
                newIndex -= 1;
              

              final item = myItems.removeAt(oldIndex);
              myItems.insert(newIndex, item);
            );
          ,
        ));
  


【问题讨论】:

【参考方案1】:

因为setState 更新了ReorderableListView,它会重新渲染整个列表,所以它不会算作更改。

您应该只更新 listView 中的一个 listTile。 为此,将您的 listTile 小部件移动到具有自己的 setStateStateful 小部件,并在主页中替换您的卡片:

class _HomePageState extends State<HomePage> 
  List myItems = [];

  @override
  void initState() 
    super.initState();
    for (int i = 0; i < 10; i++) 
      Map<String, dynamic> newTask = Map();
      newTask['task'] = 'Task #$i';
      newTask['done'] = false;
      myItems.add(newTask);
    
  

  bool a = false;

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter To Do'),
      ),
      body: ReorderableListView(
        children: [
          for (var item in myItems)
            TaskListItem(
              key: ObjectKey(item),
              item: item,
            ),
        ],
        onReorder: (oldIndex, newIndex) 
          setState(() 
            if (newIndex > oldIndex) 
              newIndex -= 1;
            

            final item = myItems.removeAt(oldIndex);
            myItems.insert(newIndex, item);
          );
        ,
      ),
    );
  

class TaskListItem extends StatefulWidget 
  final item;

  const TaskListItem(Key key, this.item) : super(key: key);

  @override
  _TaskListItemState createState() => _TaskListItemState();


class _TaskListItemState extends State<TaskListItem> 
  @override
  Widget build(BuildContext context) 
    return Card(
      margin: EdgeInsets.all(0),
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(0)),
      child: Container(
        height: 56,
        child: Row(
          children: <Widget>[
            IconButton(icon: Icon(Icons.reorder), onPressed: null),
            Expanded(
              child: Text(widget.item['task']),
            ),
            Checkbox(
              value: widget.item['done'],
              onChanged: (value) 
                setState(() 
                  widget.item['done'] = value;
                );
              ,
            )
          ],
        ),
      ),
    );
  

【讨论】:

以上是关于CheckBox 动画在 ReorderableListView 内时不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Android5.0 CheckBox颜色修改

Android CheckBox 改变边框和填充色

[WPF 自定义控件]创建包含CheckBox的ListBoxItem

jQuery点击tr实现checkbox

ListView 中的可选 TextView(缺少动画)

单选多选样式写法