You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter实现点击删除列表选中元素的问题求助

实现Todo列表项的删除功能

我想实现点击列表中的删除按钮删除对应Todo项的功能,考虑给Todo类加自增ID,但不知道该怎么加,也不清楚如何获取当前点击元素的ID。以下是我的Todo类和TodoItem组件代码:

class Todo {
  Todo({required this.name, required this.checked});

  final String name;
  bool checked;

  static Todo fromJson(Map<String, dynamic> json) {
    return Todo(name: json['name'], checked: json['checked']);
  }

  Map<String, dynamic> toJson() {
    return {
      'name': name,
      'checked': checked,
    };
  }
}

class TodoItem extends StatelessWidget {
  TodoItem({
    required this.todo,
    required this.onTap,
    required this.onDelete,
  }) : super(key: ObjectKey(todo));

  final Todo todo;
  final Function onTap;
  final Function onDelete;

  TextStyle? _getTextStyle(bool checked) {
    if (!checked) return null;

    return const TextStyle(
      color: Colors.black54,
      decoration: TextDecoration.lineThrough,
    );
  }

  @override
  Widget build(BuildContext context) {
    return ListTile(
      onTap: () {
        onTap(todo);
      },
      leading: CircleAvatar(
        child: Text(todo.name[0]),
      ),
      title: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Text(todo.name, style: _getTextStyle(todo.checked)),
          IconButton(
              onPressed: () {
                print(todo.name);
                onDelete();
              },
              icon: Icon(Icons.delete))
        ],
      ),
    );
  }
}

实现步骤

1. 给Todo类添加唯一ID

给Todo类新增id字段作为唯一标识,用自增整数即可满足需求,同时更新序列化/反序列化逻辑:

class Todo {
  Todo({required this.id, required this.name, required this.checked});

  final int id; // 新增唯一ID字段
  final String name;
  bool checked;

  static Todo fromJson(Map<String, dynamic> json) {
    return Todo(
      id: json['id'],
      name: json['name'], 
      checked: json['checked']
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'name': name,
      'checked': checked,
    };
  }
}

创建Todo实例时维护一个自增计数器生成ID:

int _nextTodoId = 0;

// 添加新Todo的示例
Todo newTodo = Todo(id: _nextTodoId++, name: '新任务', checked: false);

2. 修改TodoItem组件,传递待删除的Todo项

把无参的onDelete改为接收当前Todo实例的回调,让父组件能精准定位要删除的项:

class TodoItem extends StatelessWidget {
  TodoItem({
    required this.todo,
    required this.onTap,
    required this.onDelete,
  }) : super(key: ObjectKey(todo));

  final Todo todo;
  final Function(Todo) onTap; // 指定参数类型,代码更规范
  final Function(Todo) onDelete; // 修改为带Todo参数的回调

  TextStyle? _getTextStyle(bool checked) {
    if (!checked) return null;

    return const TextStyle(
      color: Colors.black54,
      decoration: TextDecoration.lineThrough,
    );
  }

  @override
  Widget build(BuildContext context) {
    return ListTile(
      onTap: () {
        onTap(todo);
      },
      leading: CircleAvatar(
        child: Text(todo.name[0]),
      ),
      title: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Text(todo.name, style: _getTextStyle(todo.checked)),
          IconButton(
              onPressed: () {
                onDelete(todo); // 点击删除时传递当前todo实例
              },
              icon: const Icon(Icons.delete))
        ],
      ),
    );
  }
}

3. 在父组件中实现删除逻辑

在管理Todo列表的父组件(通常是StatefulWidget的State类)里,编写删除方法并传递给TodoItem:

class TodoList extends StatefulWidget {
  const TodoList({super.key});

  @override
  State<TodoList> createState() => _TodoListState();
}

class _TodoListState extends State<TodoList> {
  final List<Todo> _todos = [];
  int _nextTodoId = 0;

  void _addTodo() {
    setState(() {
      _todos.add(Todo(id: _nextTodoId++, name: '新任务', checked: false));
    });
  }

  void _deleteTodo(Todo todo) {
    setState(() {
      // 通过ID匹配删除,比直接移除实例更稳定(避免状态更新后引用不一致)
      _todos.removeWhere((item) => item.id == todo.id);
    });
  }

  void _toggleTodo(Todo todo) {
    setState(() {
      todo.checked = !todo.checked;
    });
  }

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: _todos.map((todo) {
        return TodoItem(
          todo: todo,
          onTap: _toggleTodo,
          onDelete: _deleteTodo, // 传递删除回调
        );
      }).toList(),
    );
  }
}

为什么用ID删除而不是直接移除实例?

直接调用_todos.remove(todo)也能生效,但当Todo列表从JSON重新加载、或有其他状态更新时,可能出现实例引用不一致的情况。用唯一ID匹配删除,能确保始终删除正确的项,逻辑更稳定。

内容的提问来源于stack exchange,提问作者Fabian M

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 10:30:53