一尘不染

Flutter PaginatedDataTable rowsPerPage

flutter

能扑 PaginatedDataTable rowsPerPage 被设置为一个数字不是10整除?

更新

FutureBuilder使用的数据是从本地服务器获取的。首先,该列表包含3个项目,这将导致创建空的DataRows。

我的问题

  1. 我不想创建空的DataRows

我尝试过的

  1. 如果list-length小于defaultRowsPerPage ELSE,则将rowsPerPage计数设置为列表的长度,否则将其(rowsPerPage)设置为defaultRowsPerPage。

样本代码

import 'package:flutter/material.dart';
import 'package:nvip/constants.dart';
import 'package:nvip/data_repo/network/centers_repo.dart';
import 'package:nvip/data_repo/tables/data_source_centers.dart';
import 'package:nvip/models/vaccination_center.dart';

class VaccinationCentersTableScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) => _CentersScreenBody();
}

class _CentersScreenBody extends StatefulWidget {
  @override
  __CentersScreenBodyState createState() => __CentersScreenBodyState();
}

class __CentersScreenBodyState extends State<_CentersScreenBody> {
  int _rowsPerPage = PaginatedDataTable.defaultRowsPerPage; // This one works
  int _columnIndex = 1;
  bool _isSortAscending = true;
  Future<List<VaccineCenter>> _centers;
  CentersTableDataSource _tableDataSource;
  var _scaffoldKey = GlobalKey<ScaffoldState>();

  void _sort<T>(Comparable<T> getField(VaccineCenter c), int columnIndex,
      bool isSortAscending) {
    _tableDataSource?.sort(getField, isSortAscending);
    setState(() {
      _columnIndex = columnIndex;
      _isSortAscending = isSortAscending;
    });
  }

  @override
  void initState() {
    super.initState();
    _centers = VaccineCentersDataRepo().getCenters();
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () {
        Navigator.pushReplacementNamed(context, Routes.keyHome);
      },
      child: Scaffold(
        key: _scaffoldKey,
        appBar: AppBar(
          title: Text("Vaccination Centers"),
          centerTitle: true,
          leading: IconButton(
            icon: Icon(Constants.backIcon),
            onPressed: () {
              Navigator.pushReplacementNamed(context, Routes.keyHome);
            },
          ),
          actions: <Widget>[
            IconButton(
              icon: Icon(Icons.add),
              tooltip: "Add vaccination center",
              onPressed: () {
                Navigator.pushReplacementNamed(context, Routes.keyPovAdd);
              },
            )
          ],
        ),
        body: FutureBuilder<List<VaccineCenter>>(
          future: _centers,
          builder: (context, snapshot) {
            if (snapshot.hasError) {
              return Constants.showHasNoDataWidget(
                context,
                "No vaccination center(s) / place(s) of vaccinations found. "
                    "Press the (+) sign to add a new record.",
              );
            } else {
              if (snapshot.hasData) {
                var centerList = snapshot.data;
                var centersCount = centerList.length;
                var defaultRowsPerPage = PaginatedDataTable.defaultRowsPerPage;
                _rowsPerPage = centersCount < defaultRowsPerPage
                    ? centersCount
                    : defaultRowsPerPage;
                _tableDataSource = CentersTableDataSource(centerList);
                return SingleChildScrollView(
                  child: PaginatedDataTable(
                    header: Text("Places of Vaccination"),
                    rowsPerPage: _rowsPerPage,
                    onRowsPerPageChanged: (rowCount) {
                      setState(() {
                        _rowsPerPage = rowCount;
                      });
                    },
                    sortColumnIndex: _columnIndex,
                    sortAscending: _isSortAscending,
                    onSelectAll: (isAllChecked) =>
                        _tableDataSource?.selectAll(isAllChecked),
                    actions: <Widget>[
                      IconButton(
                        icon: Icon(Icons.add),
                        tooltip: "Add vaccination center",
                        onPressed: () {
                          Navigator.pushReplacementNamed(
                              context, Routes.keyPovAdd);
                        },
                      ),
                      IconButton(
                        icon: Icon(Icons.delete_forever),
                        tooltip: "Delete vaccination center(s).",
                        onPressed: () {
                          Constants.showSnackBar(
                              _scaffoldKey, "Delete button clicked");
                        },
                      )
                    ],
                    columns: <DataColumn>[
                      DataColumn(
                        label: Text("No."),
                        numeric: true,
                        onSort: (ci, isSortAscending) => _sort<num>(
                            (c) => centerList.indexOf(c), ci, isSortAscending),
                      ),
                      DataColumn(
                        label: Text("Name"),
                        onSort: (ci, isSortAscending) =>
                            _sort<String>((c) => c.name, ci, isSortAscending),
                      ),
                    ],
                    source: _tableDataSource,
                  ),
                );
              }
            }

            return Center(child: CircularProgressIndicator());
          },
        ),
      ),
    );
  }
}

错误日志

I/flutter ( 8474): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter ( 8474): The following assertion was thrown building FutureBuilder<List<VaccineCenter>>(dirty, state:
I/flutter ( 8474): _FutureBuilderState<List<VaccineCenter>>#92379):
I/flutter ( 8474): 'package:flutter/src/material/paginated_data_table.dart': Failed assertion: line 87 pos 19:
I/flutter ( 8474): 'availableRowsPerPage != null && availableRowsPerPage.contains(rowsPerPage)': is not true.
I/flutter ( 8474): 
I/flutter ( 8474): Either the assertion indicates an error in the framework itself, or we should provide substantially
I/flutter ( 8474): more information in this error message to help you determine and fix the underlying cause.
I/flutter ( 8474): In either case, please report this assertion by filing a bug on GitHub:
I/flutter ( 8474):   https://github.com/flutter/flutter/issues/new?template=BUG.md
I/flutter ( 8474): 
I/flutter ( 8474): When the exception was thrown, this was the stack:
I/flutter ( 8474): #2      new PaginatedDataTable.<anonymous closure> (package:flutter/src/material/paginated_data_table.dart:87:19)
I/flutter ( 8474): #3      new PaginatedDataTable (package:flutter/src/material/paginated_data_table.dart:89:9)
I/flutter ( 8474): #4      __CentersScreenBodyState.build.<anonymous closure> (package:nvip/scenes/vaccination_centers/screen_center_table.dart:86:26)
I/flutter ( 8474): #5      _FutureBuilderState.build (package:flutter/src/widgets/async.dart)
I/flutter ( 8474): #6      StatefulElement.build (package:flutter/src/widgets/framework.dart:3809:27)
I/flutter ( 8474): #7      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3721:15)
I/flutter ( 8474): #8      Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
I/flutter ( 8474): #9      BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2286:33)
I/flutter ( 8474): #10     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding&WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:676:20)
I/flutter ( 8474): #11     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:219:5)
I/flutter ( 8474): #12     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:990:15)
I/flutter ( 8474): #13     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:930:9)
I/flutter ( 8474): #14     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:842:5)
I/flutter ( 8474): #15     _invoke (dart:ui/hooks.dart:154:13)
I/flutter ( 8474): #16     _drawFrame (dart:ui/hooks.dart:143:3)
I/flutter ( 8474): (elided 2 frames from class _AssertionError)
I/flutter ( 8474): ════════════════════════════════════════════════════════════════════════════════════════════════════

更新2

我的DataTableSource

import 'package:flutter/material.dart';
import 'package:nvip/models/vaccination_center.dart';

class CentersTableDataSource extends DataTableSource {
  final List<VaccineCenter> _centers;
  int _rowsSelectedCount = 0;

  CentersTableDataSource(this._centers);

  @override
  DataRow getRow(int index) {
    assert(index >= 0);
    if (index >= _centers.length) return null;
    final VaccineCenter center = _centers[index];
    return DataRow.byIndex(
      index: index,
      selected: center.isSelected,
      onSelectChanged: (selected) {
        if (center.isSelected != selected) {
          _rowsSelectedCount += selected ? 1 : -1;
          center.isSelected = selected;
          notifyListeners();
        }
      },
      cells: <DataCell>[
        DataCell(Text("${index + 1}")),
        DataCell(Text(center.name)),
      ],
    );
  }

  @override
  bool get isRowCountApproximate => false;

  @override
  int get rowCount => _centers.length;

  @override
  int get selectedRowCount => _rowsSelectedCount;

  void sort<T extends Object>(
      Comparable<T> getField(VaccineCenter d), bool isAscending) {
    _centers.sort((a, b) {
      if (isAscending) {
        final VaccineCenter c = a;
        a = b;
        b = c;
      }

      final Comparable<T> aValue = getField(a);
      final Comparable<T> bValue = getField(b);
      return Comparable.compare(aValue, bValue);
    });
    notifyListeners();
  }

  void selectAll(bool isAllChecked) {
    _centers.forEach((center) => center.isSelected = isAllChecked);
    _rowsSelectedCount = isAllChecked ? _centers.length : 0;
    notifyListeners();
  }
}

阅读 514

收藏
2020-08-13

共1个答案

一尘不染

  import 'package:flutter/material.dart';

    class DemoTable extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return _DemoTableBody();
      }
    }

    class _DemoTableBody extends StatefulWidget {
      @override
      __DemoTableBodyState createState() => __DemoTableBodyState();
    }

    class __DemoTableBodyState extends State<_DemoTableBody> {

      int _rowsPerPage = PaginatedDataTable.defaultRowsPerPage;

      // A Variable to hold the length of table based on the condition of comparing the actual data length with the PaginatedDataTable.defaultRowsPerPage

      int _rowsPerPage1 = PaginatedDataTable.defaultRowsPerPage;

      @override
      Widget build(BuildContext context) {

      //Obtain the data to be displayed from the Derived DataTableSource

        var dts = DTS();

        // dts.rowcount provides the actual data length, ForInstance, If we have 7 data stored in the DataTableSource Object, then we will get 12 as dts.rowCount

       var tableItemsCount = dts.rowCount;

        // PaginatedDataTable.defaultRowsPerPage provides value as 10

        var defaultRowsPerPage = PaginatedDataTable.defaultRowsPerPage;

        // We are checking whether tablesItemCount is less than the defaultRowsPerPage which means we are actually checking the length of the data in DataTableSource with default PaginatedDataTable.defaultRowsPerPage i.e, 10

        var isRowCountLessDefaultRowsPerPage = tableItemsCount < defaultRowsPerPage;

        // Assigning rowsPerPage as 10 or acutal length of our data in stored in the DataTableSource Object

        _rowsPerPage =
            isRowCountLessDefaultRowsPerPage ? tableItemsCount : defaultRowsPerPage;
        return Scaffold(
          appBar: AppBar(
            title: Text("Demo Paginated Table"),
          ),
          body: SingleChildScrollView(
            child: PaginatedDataTable(
              header: Text('data with 7 rows per page'),
              // comparing the actual data length with the PaginatedDataTable.defaultRowsPerPage and then assigning it to _rowPerPage1 variable which then set using the setsState()
              onRowsPerPageChanged: isRowCountLessDefaultRowsPerPage // The source of problem!
                  ? null
                  : (rowCount) {
                      setState(() {
                        _rowsPerPage1 = rowCount;
                      });
                    },
              columns: <DataColumn>[
                DataColumn(label: Text('row')),
                DataColumn(label: Text('name')),
              ],
              source: dts,
              //Set Value for rowsPerPage based on comparing the actual data length with the PaginatedDataTable.defaultRowsPerPage 
              rowsPerPage:
                  isRowCountLessDefaultRowsPerPage ? _rowsPerPage : _rowsPerPage1,
            ),
          ),
        );
      }
    }

    class DTS extends DataTableSource {
      @override
      DataRow getRow(int index) {
        return DataRow.byIndex(
          index: index,
          cells: [
            DataCell(Text('row #$index')),
            DataCell(Text('name #$index')),
          ],
        );
      }

      @override
      int get rowCount => 9; // Manipulate this to which ever value you wish

      @override
      bool get isRowCountApproximate => false;

      @override
      int get selectedRowCount => 0;
    }
2020-08-13