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

Flutter中在顶部插入空行时的文本框异常问题求助

表格顶部插入空行的输入框异常问题

问题现象

  • 使用inputFieldKey时,新插入的顶部空行会携带上一行的数据,但文本框可正常编辑;
  • 使用UniqueKey()时,空行显示正常,但每次编辑输入框触发Widget重建时,会生成新的UniqueKey(),导致输入每个字符后光标消失,需重新点击才能继续输入。

问题背景

点击按钮触发addEmptyRow函数时,需要在表格顶部插入可正常编辑的空行,且已确认空数据已正确添加到数据源中。疑似问题出在以下代码行:

widget.mode == FormType.add ? inputFieldKey : UniqueKey(),

完整代码片段

void addEmptyRow() {
    int indexOfRow = rows.length; // Get the index of the new row
    Map<String, dynamic> emptyData = {};
    List<dynamic> columns = tableFieldDetails
        .otherFieldProperties['table_configuration']['columns'];
    String columnName = '';
    for (int columnDetails = 0;
        columnDetails < columns.length;
        columnDetails++) {
      var column = columns[columnDetails];
      columnName = column['name'];

      // Check if columnName exists in emptyData
      if (!emptyData.containsKey(columnName)) {
        emptyData[columnName] = ''; // Add columnName with empty value
      }
    }

     if (newRowPosition == 'top') {
      //need to come back to this logic, may be some other way
      tableRecords.insert(0, emptyData);
      rows.insert(0, buildSingleRow(0));
      if (indexOfRow == 0) {
        buildRows();
      }
    }
  }

  DataRow buildSingleRow(int tableRow) {
    Map<String, dynamic> record = tableRecords[tableRow];
    List<DataCell> cells = tableColumn.map<DataCell>((column) {
      String columnName = column['name'];
      String dataType = column['type'];
      dynamic cellValue = record[columnName];
      Map<String, dynamic> columnAccess = column['access'];
      
        return DataCell(
          SizedBox(
            child: buildDataCell(
                tableRow, dataTypecolumn, true,
                cellValue: cellValue),
          ),
        );
      
    }).toList();

    return DataRow(
      cells: cells,
    );
  }

Widget buildDataCell(int indexOfRow, String dataType, key, columnAccess,
      Map<String, dynamic> column, bool inputField,
      {dynamic cellValue = ''}) {
    Key inputFieldKey = Key('${column['name']}-$indexOfRow');
    //Key inputFieldKeyForEdit = Key('${column['name']}-$indexOfRow' 'edit');
    //if inputField is false, display row value as text
    if (!inputField) {
      return Center(child: Text(cellValue.toString()));
    } else {
       if (dataType == 'string') {
        return Padding(
          padding: const EdgeInsets.all(0.0),
          child: TableTextInputFieldComponent(
              column: column,
              indexOfRow: indexOfRow,
              value: cellValue,
              isStrikeThrough: isStrikeThrough,
              key: widget.mode == FormType.add ? inputFieldKey : UniqueKey(),
        );
      } else {
        return const Center(child: Text('Not supported'));
      }
    }
  }

解决方案

核心问题分析

  1. inputFieldKey的问题:插入顶部行时,新行索引为0,原第一行索引变为1。但inputFieldKey基于列名-行索引生成,Flutter的Widget复用机制会根据Key判断,导致旧行的Widget被复用给新行,从而携带旧数据。
  2. UniqueKey()的问题:每次Widget重建都会生成新的UniqueKey(),Flutter会认为这是全新的Widget,旧输入框被销毁重建,光标自然丢失。

修复方案

方案1:使用数据绑定的稳定Key(推荐)

给每条数据添加唯一标识,用该标识生成Key,确保Key与数据绑定,不受行位置变化影响。

  1. 生成空数据时添加唯一ID:
// 需引入uuid包(pub.dev/packages/uuid),或自定义生成唯一值
Map<String, dynamic> emptyData = {
  'id': const Uuid().v4(),
};
// 循环添加列名并设为空值...
  1. 修改inputFieldKey生成逻辑:
// 在buildDataCell中,获取当前行的唯一ID
String rowUniqueId = tableRecords[indexOfRow]['id'];
Key inputFieldKey = Key('${column['name']}-$rowUniqueId');
  1. 统一使用稳定Key,不再切换Key类型:
key: inputFieldKey,

方案2:强制全量刷新行(临时方案)

如果不想添加唯一ID,可移除手动插入行的逻辑,每次数据源变化后全量重建行:

  1. 修改addEmptyRow函数:
if (newRowPosition == 'top') {
  tableRecords.insert(0, emptyData);
  buildRows(); // 直接全量重建所有行,不再手动插入
}
  1. 确保buildRows()函数基于tableRecords重新生成所有rows,而非复用旧Widget。

额外修正

原代码中buildDataCell的参数传递存在错误,修正为:

buildDataCell(
  tableRow, 
  dataType, 
  columnAccess, 
  column, 
  true,
  cellValue: cellValue,
)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 08:24:59