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

Flutter ListWidget重复添加删除项问题求助

问题解决:Flutter列表重复添加/删除异常

问题描述

  • 首次添加列表条目正常,第二次开始添加会出现多个重复项,添加2个条目后列表显示4个重复项
  • 删除条目时,除第一个外其余条目会被删除两次

错误原因

核心问题出在ListView.builder的实现逻辑上:

  • 你设置了itemCount: names.length,意味着会生成与列表长度一致的条目数量
  • 但在itemBuilder中,每个条目都渲染了整个names列表转换成的Widget数组,相当于每个条目都重复显示一遍完整列表,导致内容叠加。例如names有2个元素时,ListView生成2个条目,每个条目里又显示2个Text,最终呈现2×2=4个重复项;删除时,每次removeLast减少一个元素,ListView的条目数和每个条目内的列表长度同时减少,视觉上就像删除了两次。

修正后的代码

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  static const String title = 'Flutter Sample';
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: title,
        home: Scaffold(
            appBar: AppBar(title: const Text(title)),
            body: const MyStatefulWidget()));
  }
}

class MyStatefulWidget extends StatefulWidget {
  const MyStatefulWidget({super.key});
  @override
  State<MyStatefulWidget> createState() => MyStatefulWidgetState();
}

class MyStatefulWidgetState extends State<MyStatefulWidget> {
  bool light = true;
  final List<String> names = <String>[];
  TextEditingController nc = TextEditingController();
  
  void addItemToList() {
    setState(() {
      names.add(nc.text);
    });
  }

  void deleteItemFromList() {
    setState(() {
      if(names.isNotEmpty) { // 防止空列表删除报错
        names.removeLast();
      }
    });
  }

  void clearInput() {
    setState(() {
      nc.text = "";
    });
  }

  bool x = false;

  void setInput() {
    setState(() {
      x = !x; // 原代码x != x是无效赋值,修正为取反
    });
  }

  @override
  Widget build(BuildContext context) {
    Widget test1 = const Text("Hello Flutter");
    Widget test2 = Padding(
        padding: const EdgeInsets.all(20),
        child: TextField(
            enabled: true,
            controller: nc,
            decoration: const InputDecoration(
                border: OutlineInputBorder(), labelText: 'Name')));
    Widget test3 = SwitchListTile(
        value: x,
        onChanged: (bool value) {
          setState(() {
            x = value;
          });
        });
    Widget buttons = SizedBox(
        width: 1000,
        height: 30,
        child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            mainAxisSize: MainAxisSize.min,
            children: [
              Expanded(
                  child: TextButton(
                      onPressed: clearInput, child: const Text('ClearInput'))),
              Expanded(
                  child:
                      TextButton(onPressed: addItemToList, child: const Text('Add'))),
              Expanded(
                  child: TextButton(
                      onPressed: deleteItemFromList, child: const Text('Remove')))
            ]));

    Widget mylist = ListView.builder(
        scrollDirection: Axis.vertical,
        shrinkWrap: true,
        padding: const EdgeInsets.all(8),
        itemCount: names.length,
        itemBuilder: (BuildContext context, int index) {
          // 直接返回当前索引对应的单个Text,不再渲染整个列表
          return Container(
              padding: const EdgeInsets.symmetric(vertical: 8),
              child: Text(names[index]));
        });
    
    return Scaffold( // 移除嵌套的MaterialApp,避免上下文冲突
        resizeToAvoidBottomInset: false,
        body: SingleChildScrollView(
            scrollDirection: Axis.vertical,
            child: Column(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  Container(
                      padding: const EdgeInsets.all(5),
                      child: Column(
                          mainAxisAlignment:
                              MainAxisAlignment.spaceEvenly,
                          children: <Widget>[
                            test1,
                            test2,
                            test3,
                            buttons,
                            mylist
                          ]))
                ])));
  }
}

关键修改点

  1. 修复ListView核心逻辑:在itemBuilder中直接返回当前索引对应的单个Text(names[index]),每个条目仅显示对应位置的内容,不再重复渲染整个列表
  2. 修正无效代码:将setInput方法中的x != x改为x = !x,实现开关状态取反
  3. 优化结构:移除build方法内重复的MaterialApp,避免上下文冲突
  4. 增加异常防护:在删除方法中添加空列表判断,防止数组越界报错
  5. 性能优化:给静态Widget和常量参数添加const修饰符,减少不必要的重建

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 07:05:12