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

Syncfusion Flutter DataGrid:列拖拽重排与调整大小功能异常排查

问题分析与修复方案

你的Syncfusion Flutter DataGrid列调整大小功能失效,核心问题有三个:

  1. ColumnWidthMode.fill 覆盖手动宽度控制
    开启该模式后,列宽会自动填充整个DataGrid宽度,手动设置的width属性和调整操作会被框架忽略,这是功能失效的主要原因。

  2. 初始列宽使用double.nan
    double.nan表示自动计算宽度,在fill模式下会完全由框架接管,无法触发手动调整逻辑。

  3. 列宽更新未同步到columns列表
    onColumnResizeUpdate中仅更新了columnWidths,但没有修改columns列表中对应列的width属性,导致UI无法感知宽度变化。


修复步骤

1. 移除columnWidthMode: ColumnWidthMode.fill

若需手动调整列宽,不要使用填充模式,改用固定初始宽度或自适应内容宽度。

2. 初始化有效列宽

将columnWidths的初始值从double.nan改为具体数值,示例:

late Map<String, double> columnWidths = {
  'id': 80,
  'name': 150,
  'designation': 180,
  'email': 220,
  'salary': 100,
};

3. 同步更新列宽到columns列表

在onColumnResizeUpdate中,更新columnWidths的同时,找到对应列并修改其width属性,触发UI刷新:

onColumnResizeUpdate: (ColumnResizeUpdateDetails details) {
  setState(() {
    columnWidths[details.column.columnName] = details.width;
    final index = columns.indexWhere((col) => col.columnName == details.column.columnName);
    if (index != -1) {
      columns[index] = columns[index].copyWith(width: details.width);
    }
  });
  return true;
},

修改后的完整代码

import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Syncfusion DataGrid Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  MyHomePageState createState() => MyHomePageState();
}

class MyHomePageState extends State<MyHomePage> {
  List<Employee> employees = <Employee>[];
  late List<GridColumn> columns;
  late EmployeeDataSource employeeDataSource;

  @override
  void initState() {
    super.initState();
    columns = getColumns;
    employees = getEmployeeData();
    employeeDataSource = EmployeeDataSource(employees: employees, columns: columns);
  }

  List<GridColumn> get getColumns {
    return <GridColumn>[
      GridColumn(
          columnName: 'id',
          width: columnWidths['id']!,
          label: Container(
              padding: const EdgeInsets.all(16.0),
              alignment: Alignment.center,
              child: const Text('ID'))),
      GridColumn(
          columnName: 'name',
          width: columnWidths['name']!,
          label: Container(
              padding: const EdgeInsets.all(8.0),
              alignment: Alignment.center,
              child: const Text('Name'))),
      GridColumn(
          columnName: 'designation',
          width: columnWidths['designation']!,
          label: Container(
              padding: const EdgeInsets.all(8.0),
              alignment: Alignment.center,
              child: const Text('Designation', overflow: TextOverflow.ellipsis))),
      GridColumn(
          columnName: 'email',
          width: columnWidths['email']!,
          label: Container(
              padding: const EdgeInsets.all(8.0),
              alignment: Alignment.center,
              child: const Text('Email', overflow: TextOverflow.ellipsis))),
      GridColumn(
          columnName: 'salary',
          width: columnWidths['salary']!,
          label: Container(
              padding: const EdgeInsets.all(8.0),
              alignment: Alignment.center,
              child: const Text('Salary'))),
    ];
  }

  late Map<String, double> columnWidths = {
    'id': 80,
    'name': 150,
    'designation': 180,
    'email': 220,
    'salary': 100,
  };

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Syncfusion Flutter DataGrid')),
      body: SfDataGrid(
        source: employeeDataSource,
        allowColumnsDragging: true,
        columns: columns,
        columnResizeMode: ColumnResizeMode.onResizeEnd,
        allowColumnsResizing: true,
        onColumnResizeUpdate: (ColumnResizeUpdateDetails details) {
          setState(() {
            columnWidths[details.column.columnName] = details.width;
            final index = columns.indexWhere((col) => col.columnName == details.column.columnName);
            if (index != -1) {
              columns[index] = columns[index].copyWith(width: details.width);
            }
          });
          return true;
        },
        onColumnDragging: (DataGridColumnDragDetails details) {
          if (details.action == DataGridColumnDragAction.dropped && details.to != null) {
            final GridColumn rearrangeColumn = columns[details.from];
            columns.removeAt(details.from);
            columns.insert(details.to!, rearrangeColumn);
            employeeDataSource.buildDataGridRows();
            employeeDataSource.refreshDataGrid();
          }
          return true;
        },
      ),
    );
  }
}

class EmployeeDataSource extends DataGridSource {
  EmployeeDataSource({required this.employees, required this.columns}) {
    buildDataGridRows();
  }

  void buildDataGridRows() {
    dataGridRows = employees.map<DataGridRow>((employee) {
      return DataGridRow(
          cells: columns.map<DataGridCell>((column) {
        return DataGridCell(
          columnName: column.columnName,
          value: employee[column.columnName],
        );
      }).toList());
    }).toList();
  }

  List<Employee> employees = [];
  List<GridColumn> columns = [];
  List<DataGridRow> dataGridRows = [];

  @override
  List<DataGridRow> get rows => dataGridRows;

  @override
  DataGridRowAdapter? buildRow(DataGridRow row) {
    return DataGridRowAdapter(
        cells: row.getCells().map((dataGridCell) {
      return Container(
          alignment: Alignment.center,
          padding: const EdgeInsets.symmetric(horizontal: 8.0),
          child: Text(dataGridCell.value.toString()));
    }).toList());
  }

  void refreshDataGrid() {
    notifyListeners();
  }
}

class Employee {
  Employee(this.id, this.name, this.designation, this.email, this.salary);

  final int id;
  final String name;
  final String designation;
  final String email;
  final int salary;

  operator [](Object? value) {
    if (value == 'id') return id;
    if (value == 'name') return name;
    if (value == 'designation') return designation;
    if (value == 'email') return email;
    if (value == 'salary') return salary;
    throw ArgumentError('Invalid property: $value');
  }
}

List<Employee> getEmployeeData() {
  return [
    Employee(10001, 'Jack Anderson', 'Manager', 'jack@gmail.com', 120000),
    Employee(10002, 'Olivia Wilson', 'Developer', 'olivia@gmail.com', 500000),
    Employee(10003, 'Emma Wilson', 'Developer', 'emma.wilson@gmail.com', 49000),
    Employee(10004, 'Thomas Hardy', 'Developer', 'thomas@gmail.com', 48000),
    Employee(10005, 'Mia Garcia', 'Developer', 'mia.garcia@gmail.com', 47000),
    Employee(10006, 'John Smith', 'Developer', 'john@gmail.com', 43000),
    Employee(10007, 'Maria Andres', 'Developer', 'maria@gmail.com', 41000),
    Employee(10008, 'Samuel Martinez', 'Developer', 'samuel@gmail.com', 40000),
    Employee(10009, 'Hanna Moos', 'Developer', 'hanna@gmail.com', 40000),
    Employee(10010, 'Amelia Young', 'Developer', 'amelia@gmail.com', 39000),
    Employee(10011, 'Patricio Simpson', 'Developer', 'patricio@gmail.com', 39000)
  ];
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 00:54:53