美文网首页一起来学Flutter~
Flutter 132: 图解 PaginatedDataTab

Flutter 132: 图解 PaginatedDataTab

作者: 阿策神奇 | 来源:发表于2021-08-01 07:32 被阅读0次

        小菜在尝试列表展示时,对于固定类型数据库表展示需要支持左右滑动,了解到 PaginatedDataTable 分页表格,学习一下设计思路;

    PaginatedDataTable

    源码分析

    PaginatedDataTable({
        Key key,
        @required this.header,          // 表格标题
        this.actions,                   // 标题右侧图标按钮
        @required this.columns,         // 表格表头
        this.sortColumnIndex,           // 表格索引
        this.sortAscending = true,      // 升序降序
        this.onSelectAll,               // 全选回调
        this.dataRowHeight = kMinInteractiveDimension,  // 表格行高
        this.headingRowHeight = 56.0,   // 标题高度
        this.horizontalMargin = 24.0,   // 表格外边距
        this.columnSpacing = 56.0,      // 单元格间距
        this.showCheckboxColumn = true, // 多选框显隐性
        this.initialFirstRowIndex = 0,  // 初始化起始索引
        this.onPageChanged,             // 页面切换回调
        this.rowsPerPage = defaultRowsPerPage,          // 每页数据条数
        this.availableRowsPerPage = const <int>[defaultRowsPerPage, defaultRowsPerPage * 2, defaultRowsPerPage * 5, defaultRowsPerPage * 10],   // 每页行数变更列表
        this.onRowsPerPageChanged,      // 每页数据条数变更回调
        this.dragStartBehavior = DragStartBehavior.start,
        @required this.source,          // 数据来源
    })
    

        简单分析源码可得,PaginatedDataTable 是由 DataTable 延伸而来的,并被 Card 包裹;区别在于 PaginatedDataTable 支持分页展示;

        小菜将分页表单分为五部分,分别是 DataTable 整体数据表格、DataColumn 横向数据表头、DataRow 纵向数据列表、DataCell 数据表单元格以及 DataTableSource 数据来源;

        而 PaginatedDataTable 分页数据表格也是通过 Columnheader 标题与 DataTable 数据表格以及 footer 分页按钮等封装在一起的;

    案例尝试

    1. header & columns & source

        header & columns & source 作为基本 PaginatedDataTable 三个必要属性;其中 header 作为表格的标题,不可为空,建议常用的是 Text 也可以用 ButtonBar 按钮容器,日常其他 Widget 也是可以的;

        columns 作为数据表头,是一个 DataColumn 列表,其中列表长度应与 source 资源列表数组长度一致,通过 label 来展示表头信息,也可以通过 onSort 回调来进行列表排序监听;

        source 是来自 DataTableSource 类的数据源;主要实现四个抽象方法,分别是 getRow() 根据索引获取行内容、rowCount 数据源行数、isRowCountApproximate 行数是否确定以及 selectedRowCount 选中的行数(并非选中数组而是选中数量);

    class _PaginatedPageState extends State<PaginatedDataTablePage> {
      DataTableSource _sourceData = SourceData();
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
            home: Scaffold(
                appBar: AppBar(title: Text('PaginatedDataTable Page')),
                body: Column(children: [
                  SizedBox(height: 10),
                  PaginatedDataTable(
                      source: _sourceData,
                      header: Text('Flight Products'),
                      columns: [
                        DataColumn(label: Text('Avatar')),
                        DataColumn(label: Text('ID')),
                        DataColumn(label: Text('Name')),
                        DataColumn(label: Row(children: [ Text('Price'), SizedBox(width: 5.0), Icon(Icons.airplanemode_active) ])),
                        DataColumn(label: Text('No.')),
                        DataColumn(label: Text('Address'))
                      ])
                ])));
      }
    }
    
    class SourceData extends DataTableSource {
      final List<Map<String, dynamic>> _sourceData = List.generate(
          200, (index) => {
                "avatar": (index % 3 == 1) ? 'images/icon_hzw01.jpg' : (index % 3 == 2) ? 'images/icon_hzw03.jpg' : 'images/icon_music.png',
                "id": (index + 1),
                "name": "Item Name ${(index + 1)}",
                "price": Random().nextInt(10000),
                "no.": Random().nextInt(10000),
                "address": (index % 3 == 1) ? 'Beijing' : (index % 3 == 2) ? 'New York' : 'Los Angeles'
              });
    
      bool get isRowCountApproximate => false;
    
      int get rowCount => _sourceData.length;
    
      int get selectedRowCount => 0;
    
      DataRow getRow(int index) => DataRow(cells: [
            DataCell(CircleAvatar(backgroundImage: AssetImage(_sourceData[index]["avatar"]))),
            DataCell(Text(_sourceData[index]['id'].toString())),
            DataCell(Text(_sourceData[index]['name'])),
            DataCell(Text('\$ ${_sourceData[index]['price']}')),
            DataCell(Text(_sourceData[index]['no.'].toString())),
            DataCell(Text(_sourceData[index]['address'].toString()))
          ]);
    }
    

    2. actions & headingRowHeight

        数据表的标题内容主要是通过 header 展示,而源码标题是一个 Row 结构,可以通过 actions 在右侧添加 IconWidget,类似于 ToolBar;还可以通过 headingRowHeight 调整标题行的整体高度,默认是 56.0

    header: Text('Flight Products'),
    actions: [Icon(Icons.refresh), Icon(Icons.clear)],
    headingRowHeight: 80.0,
    

    3. dataRowHeight & horizontalMargin & columnSpacing

        dataRowHeight 为数据元素行高,默认为 48.0horizontalMargin 为表格首列和尾列外边距,默认为 24.0columnSpacing 为单元格间距,默认为 56.0

    dataRowHeight: 60.0,
    horizontalMargin: 40.0,
    columnSpacing: 80.0,
    

    4. rowsPerPage & initialFirstRowIndex & onPageChanged

        rowsPerPage 为每页展示数据条数,默认为 10onPageChanged 为页面左右切换时回调,回调结果为数据索引值;initialFirstRowIndex 为初始化展示索引位置,注意,若前置数据条数不满足整数页时,取整数页前一页;

    rowsPerPage: 9,
    initialFirstRowIndex: 20,
    onPageChanged: (i) => print('onPageChanged -> $i'),
    

    5. availableRowsPerPage & onRowsPerPageChanged

        onRowsPerPageChanged 不为空时可以设置左下角每页展示行数;此时 availableRowsPerPage 列表不可为空,且小菜测试,列表首个元素需要与初始化的行数一致;

    var _rowsPerPage = 8;
    
    rowsPerPage: _rowsPerPage,
    availableRowsPerPage: [8, 16, 20],
    onRowsPerPageChanged: (value) => setState(() => _rowsPerPage = value),
    

    6. sortAscending & sortColumnIndex

        sortAscending 用于设置表格数据升序还是降序,需要配合 DataColumn 中的 onSort() 回调共同使用;sortColumnIndex 对应可升序降序的表头数组下标;

    PaginatedDataTable(
        source: _sourceData,
        header: Text('Flight Products'),
        actions: [Icon(Icons.refresh), Icon(Icons.clear)],
        headingRowHeight: 50.0,
        dataRowHeight: 60.0,
        rowsPerPage: _rowsPerPage,
        onPageChanged: (i) => print('onPageChanged -> $i'),
        availableRowsPerPage: [8, 16, 20],
        onRowsPerPageChanged: (value) => setState(() => _rowsPerPage = value),
        sortAscending: _sortAscending,
        sortColumnIndex: 1,
        columns: [
          DataColumn(label: Text('Avatar')),
          DataColumn(
              label: Text('ID'),
              onSort: (index, sortAscending) {
                setState(() {
                  _sortAscending = sortAscending;
                  _sourceData.sortData((map) => map['id'], sortAscending);
                });
              }),
          DataColumn(label: Text('Name')),
          DataColumn(label: Row(children: [Text('Price'), SizedBox(width: 5.0), ![Table06.gif](https://img.haomeiwen.com/i6187924/9fcfbafc05579b6b.gif?imageMogr2/auto-orient/strip)
    Icon(Icons.airplanemode_active) ])),
          DataColumn(label: Text('No.')),
          DataColumn(label: Text('Address'))
        ])
    
    void sortData<T>(Comparable<T> getField(Map<String, dynamic> map), bool b) {
      _sourceData.sort((Map<String, dynamic> map1, Map<String, dynamic> map2) {
        if (!b) {
          //两个项进行交换
          final Map<String, dynamic> temp = map1;
          map1 = map2;
          map2 = temp;
        }
        final Comparable<T> s1Value = getField(map1);
        final Comparable<T> s2Value = getField(map2);
        return Comparable.compare(s1Value, s2Value);
      });
      notifyListeners();
    }
    

    7. showCheckboxColumn & onSelectAll

        showCheckboxColumn 用于多选框显隐性,其前提是 DataTableSource 数据源中 DataRow 设置了 selected 属性;onSelectAll 为全选时回调,状态需要自己更新;

    showCheckboxColumn: true,
    onSelectAll: (state) => setState(() => _sourceData.selectAll(state)),
    
    DataRow getRow(int index) => DataRow.byIndex(
            index: index,
            selected: _sourceData[index]["selected"],
            onSelectChanged: (selected) {
              _sourceData[index]["selected"] = selected;
              notifyListeners();
            },
            cells: [
              DataCell(CircleAvatar(backgroundImage: AssetImage(_sourceData[index]["avatar"]))),
              DataCell(Text(_sourceData[index]['id'].toString())),
              DataCell(Text(_sourceData[index]['name'])),
              DataCell(Text('\$ ${_sourceData[index]['price']}')),
              DataCell(Text(_sourceData[index]['no.'].toString())),
              DataCell(Text(_sourceData[index]['address'].toString()))
            ]);
    
    void selectAll(bool checked) {
      _sourceData.forEach((data) => data["selected"] = checked);
      _selectCount = checked ? _sourceData.length : 0;
      notifyListeners(); //通知监听器去刷新
    }
    

        PaginatedDataTable 案例源码


        PaginatedDataTable 主要是通过 RenderObject 进行 applyPaintTransform 逐个计算单元格位置;小菜对其尝试还不够深入,如有错误,请多多指导!

    来源: 阿策小和尚

    相关文章

      网友评论

        本文标题:Flutter 132: 图解 PaginatedDataTab

        本文链接:https://www.haomeiwen.com/subject/ftxzmltx.html