Flutter DataTable固定顶部行、左右列实现方案咨询
实现Flutter DataTable表头、左右列冻结方案
原生DataTable没有内置冻结列/表头的功能,我们可以通过组合SingleChildScrollView、Row、Column等基础Widget,配合滚动控制器同步来实现需求。
核心实现思路
- 将表格拆分为顶部固定表头、左侧固定列、中间可滚动列、右侧固定列四个模块
- 用垂直
ScrollController同步左侧、中间、右侧列的垂直滚动位置,保证行对齐 - 中间列单独用水平
SingleChildScrollView实现横向滚动
完整代码示例
import 'package:flutter/material.dart'; class FrozenDataTable extends StatefulWidget { const FrozenDataTable({super.key}); @override State<FrozenDataTable> createState() => _FrozenDataTableState(); } class _FrozenDataTableState extends State<FrozenDataTable> { // 同步垂直滚动的控制器 final ScrollController _verticalController = ScrollController(); // 模拟表格数据 final List<List<String>> _tableData = List.generate( 50, (index) => [ '行$index', '数据${index}A', '数据${index}B', '数据${index}C', '数据${index}D', '数据${index}E', '固定右列$index', ], ); // 统一行高,避免滚动错位 static const double _rowHeight = 56; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('冻结列示例')), body: Column( children: [ // 顶部固定表头 _buildHeaderRow(), // 表格内容区域(垂直滚动) Expanded( child: SingleChildScrollView( controller: _verticalController, child: Column( children: List.generate( _tableData.length, (rowIndex) => SizedBox( height: _rowHeight, child: Row( children: [ // 左侧固定列 _buildFixedLeftCell(_tableData[rowIndex][0]), // 中间可滚动列 SizedBox( width: MediaQuery.of(context).size.width - 240, // 减去左右固定列宽度 child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: _tableData[rowIndex] .sublist(1, 6) .map((cell) => _buildScrollableCell(cell)) .toList(), ), ), ), // 右侧固定列 _buildFixedRightCell(_tableData[rowIndex][6]), ], ), ), ), ), ), ), ], ), ); } // 构建表头行 Widget _buildHeaderRow() { return SizedBox( height: _rowHeight, child: Row( children: [ _buildFixedLeftCell('固定左列'), SizedBox( width: MediaQuery.of(context).size.width - 240, child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: const [ _HeaderCell(text: '列A'), _HeaderCell(text: '列B'), _HeaderCell(text: '列C'), _HeaderCell(text: '列D'), _HeaderCell(text: '列E'), ], ), ), ), _buildFixedRightCell('固定右列'), ], ), ); } // 左侧固定单元格 Widget _buildFixedLeftCell(String text) { return Container( width: 120, height: _rowHeight, alignment: Alignment.centerLeft, padding: const EdgeInsets.symmetric(horizontal: 16), decoration: const BoxDecoration( border: Border( right: BorderSide(color: Colors.grey), bottom: BorderSide(color: Colors.grey), ), color: Colors.grey[50], ), child: Text(text, style: const TextStyle(fontWeight: FontWeight.bold)), ); } // 右侧固定单元格 Widget _buildFixedRightCell(String text) { return Container( width: 120, height: _rowHeight, alignment: Alignment.centerLeft, padding: const EdgeInsets.symmetric(horizontal: 16), decoration: const BoxDecoration( border: Border( left: BorderSide(color: Colors.grey), bottom: BorderSide(color: Colors.grey), ), color: Colors.grey[50], ), child: Text(text), ); } // 中间滚动单元格 Widget _buildScrollableCell(String text) { return Container( width: 150, height: _rowHeight, alignment: Alignment.centerLeft, padding: const EdgeInsets.symmetric(horizontal: 16), decoration: const BoxDecoration( border: Border( right: BorderSide(color: Colors.grey), bottom: BorderSide(color: Colors.grey), ), ), child: Text(text), ); } } // 表头单元格组件 class _HeaderCell extends StatelessWidget { final String text; const _HeaderCell({required this.text}); @override Widget build(BuildContext context) { return Container( width: 150, height: _FrozenDataTableState._rowHeight, alignment: Alignment.centerLeft, padding: const EdgeInsets.symmetric(horizontal: 16), decoration: const BoxDecoration( border: Border( right: BorderSide(color: Colors.grey), bottom: BorderSide(color: Colors.grey), ), color: Colors.grey[100], ), child: Text(text, style: const TextStyle(fontWeight: FontWeight.bold)), ); } }
关键注意事项
- 统一行高:必须保证所有行(表头和内容行)的高度一致,否则垂直滚动时会出现错位问题
- 滚动同步:如果左侧/右侧列需要单独滚动,要为它们各自创建
ScrollController,并在addListener中同步彼此的offset - 性能优化:如果数据量极大,建议用
ListView.builder替代List.generate,避免一次性创建大量Widget - 自适应宽度:示例中固定了左右列的宽度,实际开发中可以根据需求调整,或者使用
LayoutBuilder动态计算宽度
内容的提问来源于stack exchange,提问作者kk-at-cbx
相关产品推荐
相关产品推荐

