10、 Flutter Widgets 之 DataTable表格数据

4,168 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天,点击查看活动详情

前言:

DataTable 这个名字在大前端开发一定不陌生吧,与之同名的DataTable前端框架,大家都使用得很娴熟了,这个框架用于做为后台的数据展示跟操作,那么,在Flutter同样也是用于数据展示跟操作,Flutter里面怎么使用呢?让我们来一起学习吧!

1.DataTable介绍

数据表显示表格数据,需要设置行和列

2.DataTable属性

属性介绍
columns@required 列数组
sortColumnIndex有排列箭头的列,仅仅是展示箭头
sortAscending是否升序,默认为 true, 排列顺序,仅仅是箭头向上还是向下
onSelectAll左上角全选按钮点击回调
dataRowHeightRows 中每条 Row 高度,默认为 kMinInteractiveDimension = 48.0
headingRowHeight顶部 Row 高度,默认为 56.0
horizontalMargin左侧边距,默认为 24.0
columnSpacing每一列间距,默认为 56.0
showCheckboxColumn是否展示左侧 checkbox 这一列,默认为 true
dividerThickness分割线宽度,默认为 1.0
rows@required 行数组

3.DataColumn属性

属性介绍
label文本
tooltip长按提示
numeric是否居右,默认为 false
onSort点击排序箭头回调函数

4.DataRow属性

属性介绍
selectedcheckbox 是否选中,默认为 false
onSelectChanged左侧 checkbox 点击事件
colorDataRow 颜色回调函数
cells 数组

5.DataCell属性

属性介绍
child子组件
placeholder是否为 placeholder,会改变 Text 样式
showEditIcon是否展示编辑按钮
onTap点击事件

6.DataTable基本用法

  • 一个基础的DataTable需要设置columns列,rows行

  • 由于DataTable本身是不具备滑动属性,所以当数据比较多的时候需要嵌套滑动组件,使用两个SingleChildScrollView来完成纵向横向的滑动

代码案例:

   /**
 * @Author wywinstonwy
 * @Date 2021/12/28 9:45 下午
 * @Description:
 */
import 'package:demo202112/utils/common_appbar.dart';
import 'package:flutter/material.dart';
 
 class WyDataTable extends StatefulWidget {
   const WyDataTable({Key? key}) : super(key: key);
 
   @override
   _WyDataTableState createState() => _WyDataTableState();
 }
 
 class _WyDataTableState extends State<WyDataTable> {
   @override
   Widget build(BuildContext context) {
     return Scaffold(
       appBar: getAppBar('DataTable'),
       body: _baseDataTable(),
     );
   }
   _baseDataTable(){
     return DataTable(
       columns: [
         DataColumn(label: Text('姓名')),
         DataColumn(label: Text('年龄')),
       ],
       rows: [
         DataRow(cells: [
           DataCell(Text('老王')),
           DataCell(Text('26')),
         ]),
         DataRow(cells: [
           DataCell(Text('老李')),
           DataCell(Text('16')),
         ]),
         DataRow(cells: [
           DataCell(Text('老李')),
           DataCell(Text('16')),
         ]),
       ],
     );
   }
 } 

运行效果:

图片.png

在表头显示排序图标:

DataTable(
  sortColumnIndex: 1,
  sortAscending: true,
  ...
  )

sortColumnIndex参数表示表格显示排序图标的索引,sortAscending参数表示升序或者降序,效果如下:

图片.png

DataColumn

默认情况下数据是左对齐的,让某一列右对齐只需设置DataColumn中numeric参数true,设置如下:

    DataTable(
  columns: [
    DataColumn(label: Text('姓名')),
    DataColumn(label: Text('年龄'),numeric: true),
  ],
  ...
  ) 

运行效果:

图片.png

设置DataColumn中tooltip参数表示当长按此表头时显示提示,用法如下:

    DataColumn(label: Text('姓名'),tooltip: '长按提示')

图片.png

onSort回调是用户点击表头(DataColumn)时的回调,onSort中第一个参数columnIndex表示索引,ascending参数表示升序或者降序,用法如下:

   DataColumn(label: Text('年龄'), onSort: (int columnIndex, bool ascending){
   //排序算法
}),

DataRow

可以显示其中一行被选中,设置DataRow中selected参数为true,用法如下:

   DataRow(
 selected: true,
 ...
)

运行效果:

图片.png

onSelectChanged参数是点击每一行数据时的回调,用法如下:

   DataRow(
   onSelectChanged: (selected){
   }
   ...
)

设置了onSelectChanged参数,在数据的每一行和表头的前面显示勾选框,效果如下:

图片.png

当然现在点击还不能显示选中的效果,增加选中效果,修改User model类,增加selected属性,表示当前行是否选中:

   class User {
 User(this.name, this.age, {this.selected = false});

 String name;
 int age;
 bool selected;
}

修改数据:

    List<User> data = [
     User('老往', 18),
     User('老李1', 19,selected: true),
     User('老张2', 20),
     User('老舍3', 21),
     User('老牛4', 22),
   ];

构建DataTable:

       List<DataRow> dataRows = [];
     for(int i=0;i<data.length;i++){
       dataRows.add(DataRow(
          selected: data[i].selected,
           onSelectChanged: (selected){
            setState(() {
              data[i].selected = selected!;
            });
           },
           cells: [
             DataCell(Text('${data[i].name}')),
             DataCell(Text('${data[i].age}')),
           ]));
     }
     return DataTable(
         columns: [
           DataColumn(label: Text('姓名')),
           DataColumn(label: Text('年龄')),
         ],
         rows: dataRows);
   }

运行效果:

图片.png

我们并没有对表头的全选/取消全选勾选框进行控制,一个很大的疑问:点击全选/取消全选勾选框,如果都勾选了,真实数据是否也发生变化了,对应本示例就是User中的selected参数是否全部为true,可以肯定的告诉你User中的selected参数已经全部变为true了,那是如何实现的呢?非常简单,每一行的onSelectChanged都被回调了一次。

DataCell

DataCell是DataRow中每一个子控件,DataCell子控件不一定是文本,也可以是图标等任意组件,我们可以给DataCell设置编辑图标:

DataCell(Text('${data[i].age}'),showEditIcon: true),

运行效果:

图片.png

当然仅仅是一个图标,placeholder参数也是一样的,设置为true,仅仅是文字的样式变化了,onTap为点击回调,用法如下:

 DataCell(Text('${data[i].age}'),showEditIcon: true,onTap: (){
              print('${data[i].age}');
            },placeholder: true),                                    

图片.png

排序

DateTable本身是没有排序功能的,当用户点击表头时对数据按照本列数据进行排序,用法如下,

数据model类:

/**
 * @Author wywinstonwy
 * @Date 2021/12/28 9:45 下午
 * @Description:
 */
import 'package:demo202112/utils/common_appbar.dart';
import 'package:flutter/material.dart';
 
 class WyDataTable extends StatefulWidget {
   const WyDataTable({Key? key}) : super(key: key);
 
   @override
   _WyDataTableState createState() => _WyDataTableState();
 }
 
 class _WyDataTableState extends State<WyDataTable> {
   List<User> data = [
     User('老往', 18),
     User('老李1', 19,selected: true),
     User('老张2', 20),
     User('老舍3', 21),
     User('老牛4', 22),
   ];
   var _sortAscending = true;
   @override
   Widget build(BuildContext context) {
     return Scaffold(
       appBar: getAppBar('DataTable'),
       body: _buildDataRows(),
     );
   }
   _baseDataTable(){
     return DataTable(
       sortColumnIndex: 1,
       sortAscending: true,
       columns: [
         DataColumn(label: Text('姓名'),tooltip: '长按提示'),
         DataColumn(label: Text('年龄'),numeric: true,onSort: (int columnIndex,bool ascending){
           //排序算法
 
         }),
       ],
       rows: [
         DataRow(cells: [
           DataCell(Text('老王')),
           DataCell(Text('26')),
         ]),
         DataRow(
           selected: true,
             onSelectChanged: (selected){
             print(selected);
             },
             cells: [
           DataCell(Text('老李')),
           DataCell(Text('16')),
         ]),
         DataRow(cells: [
           DataCell(Text('老李')),
           DataCell(Text('16')),
         ]),
       ],
     );
   }
   _buildDataRows(){
     List<DataRow> dataRows = [];
     for(int i=0;i<data.length;i++){
       dataRows.add(DataRow(
          selected: data[i].selected,
           onSelectChanged: (selected){
            setState(() {
              data[i].selected = selected!;
            });
           },
           cells: [
             DataCell(Text('${data[i].name}')),
             DataCell(Text('${data[i].age}')
             ),
           ]));
     }
     return DataTable(
         sortColumnIndex: 1,
         sortAscending: true,
         columns: [
           DataColumn(label: Text('姓名')),
           DataColumn(label: Text('年龄'),onSort: (int columnIndex,bool ascending){
             setState(() {
               _sortAscending = ascending;
               if(ascending){
                 data.sort((a,b)=>a.age.compareTo(b.age));
               }else{
                 data.sort((a, b) => b.age.compareTo(a.age));
               }
             });
           }),
         ],
         rows: dataRows);
   }
 }
 
class User {
  User(this.name, this.age, {this.selected = false});
 
  String name;
  int age;
  bool selected;
}                                     

运行效果:

图片.png

处理数据显示不全问题

当表格列比较多的时候,可以使用SingleChildScrollView包裹DataTable,显示不全时滚动显示,用法如下:

 _buildDataRows(){
     List<DataRow> dataRows = [];
     for(int i=0;i<data.length;i++){
       dataRows.add(DataRow(
          selected: data[i].selected,
           onSelectChanged: (selected){
            setState(() {
              data[i].selected = selected!;
            });
           },
           cells: [
             DataCell(Text('${data[i].name}')),
             DataCell(Text('${data[i].age}'),),
             DataCell(Text('${data[i].address}'),),
             DataCell(Text('${data[i].birthday}'),),
             DataCell(Text('${data[i].birthday1}'),),
           ]));
     }
     return SingleChildScrollView(
       scrollDirection: Axis.horizontal,
       child: DataTable(
           sortColumnIndex: 1,
           sortAscending: true,
           columns: [
             DataColumn(label: Text('姓名')),
             DataColumn(label: Text('年龄'),onSort: (int columnIndex,bool ascending){
               setState(() {
                 _sortAscending = ascending;
                 if(ascending){
                   data.sort((a,b)=>a.age.compareTo(b.age));
                 }else{
                   data.sort((a, b) => b.age.compareTo(a.age));
                 }
               });
             }),
             DataColumn(label: Text('地址')),
             DataColumn(label: Text('出身日期')),
             DataColumn(label: Text('出身日期')),
 
           ],
           rows: dataRows),
     );
   }    

运行效果:

图片.png

第三方组件

除了flutter系统提供的以外,可以参考pub.dev第三方组件,如# data_tables等。。

技术总结:

本篇主要介绍了DataTable的属性和基础使用,选择,排序,左右横滑。此外有粉丝提到如何添加滚动进度条,可以外层包裹Scrollbar,flutter万物皆组件, 如果既要横向滚动,又要纵向滚动,该如何解决呢?这个问题可以自己写代码调试,如有问题可以评论区留言讨论。