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

Flutter DataTable多行选择实现及重复行异常问题解决

问题分析与解决方案

问题根源

  1. 全局选中状态导致批量异常:原代码用单个bool checked变量控制所有行的选中状态,点击任意一行时,所有行的选中状态会同步切换,出现自动选中多行的异常。
  2. 表头与数据不匹配:表头中第四项是“SUPPLIER”,但对应单元格显示的是productId数据,导致内容错位。
  3. 无用变量冗余:State中定义的selectedIndex和itemListData未实际发挥作用,造成代码冗余。

修复后的完整代码

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import '../defaults/defaults.dart';
import 'items/additem.dart';
        
class SearchItem extends StatefulWidget {
    const SearchItem({Key? key}) : super(key: key);       
    @override
    State<SearchItem> createState() => _SearchItemState();
}

class _SearchItemState extends State<SearchItem> {
    // 存储选中的文档ID,实现独立的多行选择
    final Set<String> selectedItemIds = {};

    List<DataCell> _createCellsForElement(DocumentSnapshot document) {
        Map<String, dynamic> data = document.data() as Map<String, dynamic>;
        return <DataCell>[
            DataCell(Text(data['itemid'].toString(), style: Defaults.drawerTextBlacknormal)),
            DataCell(Text(data['isbn'].toString(), style: Defaults.drawerTextBlacknormal)),
            DataCell(Text(data['itemName'].toString(), style: Defaults.drawerTextBlacknormal)),
            // 修正表头与数据的对应关系,优先显示supplier字段,不存在则保留productId
            DataCell(Text(data['supplier']?.toString() ?? data['productId'].toString(), style: Defaults.drawerTextBlacknormal)),
            DataCell(Text(data['category'].toString(), style: Defaults.drawerTextBlacknormal)),
            DataCell(Text(data['costPrice'].toString(), style: Defaults.drawerTextBlacknormal)),
            DataCell(Text(data['quantity'].toString(), style: Defaults.drawerTextBlacknormal)),
            DataCell(Text(data['sellingPrice'].toString(), style: Defaults.drawerTextBlacknormal)),
            DataCell(Text(data['amount'].toString(), style: Defaults.drawerTextBlacknormal)),
            DataCell(Text(data['promoEndDt'].toString(), style: Defaults.drawerTextBlacknormal)),
            DataCell(IconButton(onPressed: () {}, icon: const Icon(Icons.delete))),
        ];
    }

    // 表头列表,修正顺序与数据对应
    final columns = [
        'ID',
        'UPC/EAN/ISBN',
        'ITEM NAME',
        'SUPPLIER',
        'CATEGORY',
        'COST PRICE',
        'QUANTITY',
        'SELLING PRICE',
        'AMOUNT',
        'EXPIRY DATE',
        'DELETE'
    ];

    List<DataColumn> getcolumns(List<String> columns) => columns
        .map((String column) => DataColumn(
            label: Text(column, style: Defaults.drawerTextBlacknormal))).toList();

    @override
    Widget build(BuildContext context) {
        return Align(
            alignment: Alignment.center,
            child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                mainAxisSize: MainAxisSize.min,
                children: [
                    Text('Item List', style: Defaults.drawerTextStyleHeadBlack),
                    Container(
                        margin: const EdgeInsets.fromLTRB(20, 30, 20, 0),
                        child: StreamBuilder<QuerySnapshot>(
                            stream: FirebaseFirestore.instance.collection('ItemsCollection').snapshots(),
                            builder: (context, snapshot) {
                                if (snapshot.hasError) {
                                    return const Text('Something went Wrong!');
                                } else if (snapshot.hasData) {
                                    final itemListData = snapshot.data!.docs.map((doc) {
                                        return DataRow(
                                            cells: _createCellsForElement(doc),
                                            // 判断当前文档是否被选中
                                            selected: selectedItemIds.contains(doc.id),
                                            onSelectChanged: (bool? isSelected) {
                                                setState(() {
                                                    if (isSelected == true) {
                                                        selectedItemIds.add(doc.id);
                                                    } else {
                                                        selectedItemIds.remove(doc.id);
                                                    }
                                                });
                                            }
                                        );
                                    }).toList();

                                    return SingleChildScrollView(
                                        scrollDirection: Axis.horizontal,
                                        clipBehavior: Clip.hardEdge,
                                        child: InteractiveViewer(
                                            alignPanAxis: true,
                                            child: DataTable(
                                                columnSpacing: 20,
                                                sortAscending: true,
                                                columns: getcolumns(columns),
                                                rows: itemListData,
                                            ),
                                        ),
                                    );
                                } else {
                                    return const Center(child: CircularProgressIndicator());
                                }
                            },
                        ),
                    ),
                ],
            ),
        );
    }
}

关键修改说明

  1. 多行选择实现:用Set<String> selectedItemIds存储选中的文档ID,每个行的选中状态独立,点击行时仅更新当前行对应的ID在集合中的存在状态。
  2. 修正数据与表头匹配:调整第四列的单元格数据,优先显示supplier字段(如果Firestore文档中有该字段),否则保留原productId,确保与表头“SUPPLIER”对应。
  3. 简化行列表构建:用map替代循环构建行列表,代码更简洁,避免冗余的索引变量。
  4. 移除无用变量:删除State中未使用的selectedIndex和itemListData,减少代码冗余。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 16:48:58