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

Flutter中SFDataGrid搭配SFDataPager分页失效问题求助

Flutter Syncfusion DataGrid 分页失效问题修复

问题核心

使用syncfusion_flutter_datagrid的SfDataPager时分页功能完全失效:

  • 计算得出的pageCount正确(15条数据分2页),但rowsPerPage配置不生效
  • DataGrid仍显示全部15条数据并保持可滚动状态
  • SfDataGrid和SfDataPager均已关联DataGridSource,但分页操作无任何响应

错误原因

  1. DataGridSource实例不共享:SfDataGrid和SfDataPager各自创建了独立的DTRHistoryDataGridSource实例,两者数据状态完全隔离,分页器的操作无法同步到DataGrid
  2. 缺失分页逻辑实现:自定义的DTRHistoryDataGridSource未重写handlePageChange方法,无法响应分页器的页码切换事件
  3. 每页条数配置冲突:SfDataGrid设置rowsPerPage:11,但分页器按10条一页计算,数值不统一导致分页逻辑混乱

修复步骤

  1. 共享DataGridSource实例:在父组件中创建唯一的DTRHistoryDataGridSource实例,同时传递给SfDataGrid和SfDataPager
  2. 完善分页逻辑:在DTRHistoryDataGridSource中重写handlePageChange方法,根据页码和每页条数筛选数据并通知DataGrid刷新
  3. 统一每页条数:保持SfDataGrid的rowsPerPage与分页器的计算逻辑一致

修改后的代码

1. 父视图组件修改

// 在父组件中初始化共享的DataGridSource实例
final DTRHistoryDataGridSource _dataSource = DTRHistoryDataGridSource(
  dtrHistoryData: _controller.historyData.value,
);

// 组件渲染部分
AppDataGrid(
  dtrHistoryData: _controller.historyData.value,
  columns: _controller.columns,
  dataSource: _dataSource, // 传入共享实例
),
SizedBox(
  height: dataPagerHeight,
  width: double.maxFinite,
  child: Center(
    child: SfDataPager(
      pageCount: ((_controller.historyData.value.timeData?.length ?? 0) / 10).ceilToDouble(),
      delegate: _dataSource, // 使用同一个数据源实例
      direction: Axis.horizontal,
    ),
  ),
),

2. AppDataGrid组件修改

import 'package:flutter/material.dart';
import 'package:puncher_app/app/global/constants/colors.dart';
import 'package:puncher_app/app/models/dtr_history_data.dart';
import 'package:syncfusion_flutter_core/theme.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';

import '../../data/table/history_table2_data.dart';

class AppDataGrid extends StatelessWidget {
  final DTRHistoryData dtrHistoryData;
  final List<GridColumn> columns;
  final DTRHistoryDataGridSource dataSource; // 添加数据源参数

  const AppDataGrid({
    super.key,
    required this.dtrHistoryData,
    required this.columns,
    required this.dataSource, // 接收共享实例
  });

  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: Card(
        clipBehavior: Clip.antiAliasWithSaveLayer,
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
        color: transparent,
        elevation: 0,
        child: SfDataGridTheme(
          data: SfDataGridThemeData(
            headerColor: secondaryColor,
          ),
          child: SfDataGrid(
            rowsPerPage: 10, // 和分页器保持一致
            verticalScrollPhysics: const ClampingScrollPhysics(),
            horizontalScrollPhysics: const ClampingScrollPhysics(),
            headerGridLinesVisibility: GridLinesVisibility.none,
            gridLinesVisibility: GridLinesVisibility.horizontal,
            source: dataSource, // 使用共享实例
            columns: columns,
          ),
        ),
      ),
    );
  }
}

3. DTRHistoryDataGridSource修改

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:puncher_app/app/global/constants/colors.dart';
import 'package:puncher_app/app/global/constants/styles.dart';
import 'package:puncher_app/app/global/widgets/app_text.dart';
import 'package:puncher_app/app/models/dtr_history_data.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';

class DTRHistoryDataGridSource extends DataGridSource {
  late List<DataGridRow> _dtrHistoryDataGridRows;
  late List<TimeData> _originalData; // 保存原始全量数据
  final int _rowsPerPage = 10; // 统一每页条数

  DTRHistoryDataGridSource({required DTRHistoryData dtrHistoryData}) {
    _originalData = dtrHistoryData.timeData ?? [];
    buildDataGridRows(0); // 初始化加载第一页数据
  }

  // 根据页码构建当前页数据
  void buildDataGridRows(int pageIndex) {
    final dateFormat = DateFormat('hh:mm a');
    final startIndex = pageIndex * _rowsPerPage;
    final endIndex = startIndex + _rowsPerPage;
    final currentPageData = _originalData.sublist(
      startIndex,
      endIndex > _originalData.length ? _originalData.length : endIndex,
    );

    _dtrHistoryDataGridRows = currentPageData
        .map<DataGridRow>(
          (timeData) => DataGridRow(
            cells: [
              DataGridCell<String>(
                columnName: 'Date',
                value: timeData.date,
              ),
              DataGridCell<String>(
                columnName: 'Time In',
                value: timeData.timeIn?.isNotEmpty == true
                    ? dateFormat.format(DateTime.parse(timeData.timeIn!))
                    : '--',
              ),
              DataGridCell<String>(
                columnName: 'Time Out',
                value: timeData.timeOut?.isNotEmpty == true
                    ? dateFormat.format(DateTime.parse(timeData.timeOut!))
                    : '--',
              ),
              DataGridCell<String>(
                columnName: 'Duration',
                value: timeData.duration != null
                    ? formatDuration(timeData.duration!)
                    : '--',
              )
            ],
          ),
        )
        .toList();
  }

  String formatDuration(String duration) {
    final parts = duration.split(' ');
    final hours = parts[0];
    final minutes = parts[2];
    return '${hours}h${minutes}m';
  }

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

  @override
  DataGridRowAdapter buildRow(DataGridRow row) {
    return DataGridRowAdapter(
        cells: row.getCells().map<Widget>((dataGridCell) {
      return Container(
          alignment: Alignment.center,
          child: AppText(
            text: dataGridCell.value.toString(),
            textColor: secondaryColor,
            style: kRegTextBlack,
            alignment: TextAlign.center,
          ));
    }).toList());
  }

  @override
  Object getValue(int rowIndex, String columnName) {
    final TimeData timeData = _originalData[rowIndex];
    switch (columnName) {
      case 'Date':
        return timeData.date!;
      case 'Time In':
        return timeData.timeIn!;
      case 'Time Out':
        return timeData.timeOut!;
      case 'Duration':
        return timeData.duration!;
      default:
        return '';
    }
  }

  // 重写分页切换方法,响应SfDataPager的页码变化
  @override
  Future<void> handlePageChange(int oldPageIndex, int newPageIndex) async {
    buildDataGridRows(newPageIndex);
    notifyListeners(); // 通知DataGrid刷新当前页数据
    return super.handlePageChange(oldPageIndex, newPageIndex);
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 07:52:57