在 Flutter 中动态显示数据表布局中的 JSON 数据

Posted

技术标签:

【中文标题】在 Flutter 中动态显示数据表布局中的 JSON 数据【英文标题】:Dynamically display JSON data in data table layout in flutter 【发布时间】:2021-04-27 13:46:41 【问题描述】:

我正在 flutter 中创建一个动态数据表视图,其中列标题和行值是动态添加的。数据是一个 Json 响应,标题是一个字符串数组,要在行中显示的数据也是一个字符串数组。目标是在表格视图中显示数据,而不需要任何硬编码值。 这就是我尝试显示数据的方式。

                     return ListView.builder(
                         shrinkWrap: true,
                         scrollDirection: Axis.vertical,
                         itemCount: snapshot.data.dataList.length,
                         itemBuilder: (BuildContext context, int index)
                           return SingleChildScrollView(
                             child: DataTable(
                               columns: (snapshot.data.headerList[index] as List).map((item) =>
                               DataColumn(
                                   label:(
                                       List.generate(item.length,(index)
                                         return Text(item[index].toString());
                                       )
                                   )
                               )).toList(),
                               rows: (snapshot.data.dataList[index].dataList as List).map((item) =>
                               
                               DataRow(
                                 
                                   cells:<DataCell>[
                                     DataCell(
                                         List.generate(item.length,(index)
                                           return Text(item[index].toString());
                                         )
                                     )
                                    ])).toList(),
                             ),

这是 JSON 响应

 "DayEnd": 
        "ColumnWidths": "40´168´96´96´108´156",
        "Headers": "SL.>´Customer< ´Balance Qty>´Amount>´Oldest / Recent ",
        "FieldSeparator": "´",
        "DataList": [
            
                "Data": "1. ´ABD ´14 / 14.60´11,090´313 / 313",
                "NextLevelZoomData": [
                    
                        "Element": "eg7P27fbW/GmCr"
                    ,
                    
                        "Element": "AAA=="
                    
                ],
                "NextLevelZoomType": 2
            ,
            
                "Data": "2. ´LATA´16´7,921´20 / 9",
                "NextLevelZoomData": [
                    
                        "Element": "MT63z0m7piukmtJZqdZ"
                    ,
                    
                        "Element": "QT/2zE/AAA="
                    
                ],
                "NextLevelZoomType": 2
            ,
            
                "Data": "3. ´ANAND´11´915´426 / 426",
                "NextLevelZoomData": [
                    
                        "Element": "AAA="
                    
                ],
                "NextLevelZoomType": 2
            ,
            
                "Data": "4. ´Asts´1´1,010´27 / 27",
                "NextLevelZoomData": [
                    
                        "Element": "w/VbTHwKgQAAA=="
                    
                ],
                "NextLevelZoomType": 2
            ,
            

上面的响应给出了一个字符串数据Headers,由一个特殊字符“`”分隔,每个字符必须显示在每个列标题中,以便转换为数组。同样的数据也是如此。 columnWidth 中提到了必须为每个数据维护的列宽 同样,数据的对齐方式如 if "SL.>" then ">" 它必须是右对齐的。

我不确定这是否是获取它的正确方法,这会出错

The argument type 'List<Text>' can't be assigned to the parameter type 'Widget'.

任何以更好的方式接近的想法将不胜感激。

【问题讨论】:

如果可能,请添加您的 json 响应 @ShubhamNarkhede 添加了 json 响应 【参考方案1】:

第 1 步:

[
  
    "DayEnd": [
      
        "ColumnWidths": "40´168´96´96´108´156",
        "Headers": "SL.>´Customer< ´Balance Qty>´Amount>´Oldest / Recent ",
        "FieldSeparator": "´",
        "DataList": [
          
            "Data": "1. ´ABD ´14 / 14.60´11,090´313 / 313",
            "NextLevelZoomData": [
              
                "Element": "eg7P27fbW/GmCr"
              ,
              
                "Element": "AAA=="
              
            ],
            "NextLevelZoomType": 2
          
        ]
      
    ]
  
]

第 2 步:

 class TableModel 
  TableModel(this.headerData, this.rowData);
  List<String> headerData;
  List<List<String>> rowData;

  factory TableModel.fromJson(Map<String, dynamic> json) 
    return TableModel(
      json['DayEnd'][0]["Headers"].split('´').toList(),
      buildRowData(json),
    );
  


List<List<String>> buildRowData(Map<String, dynamic> json)
  List<List<String>> rowDataCollection = [];
  json['DayEnd'][0]["DataList"].forEach((rows)
    rowDataCollection.add(rows['Data'].split('´').toList());
  );

  return rowDataCollection;

第 3 步:

Future<void> generateList() async 
    String responseBody = await rootBundle.loadString("assets/data.json");
    var list = await json.decode(responseBody).cast<Map<String, dynamic>>();
    return await list
        .map<TableModel>((json) => TableModel.fromJson(json))
        .toList();
  

  @override
  Widget build(BuildContext context) 
    return SafeArea(
        child: Scaffold(
            appBar: AppBar(
              title: Text('DataTable'),
            ),
            body: FutureBuilder(
              future: generateList(),
              builder: (context, snapShot) 
                if (snapShot.data == null ||
                    snapShot.connectionState == ConnectionState.waiting ||
                    snapShot.hasError ||
                    snapShot.data.length == 0) 
                  return Container(
                    child: Center(child: CircularProgressIndicator()),
                  );
                 else 
                  return ListView.builder(
                      shrinkWrap: true,
                      scrollDirection: Axis.vertical,
                      itemCount: snapShot.data.length,
                      itemBuilder: (BuildContext context, int index) 
                        final TableModel table = snapShot.data[index];
                        return SingleChildScrollView(
                          scrollDirection: Axis.horizontal,
                          child: DataTable(
                            columns: table.headerData.map<DataColumn>((e) 
                              var columnName = e;
                              TextAlign align;
                              if (columnName.contains('<')) 
                                align = TextAlign.start;
                                columnName = columnName.replaceAll('<', '');
                               else if (columnName.contains('>')) 
                                align = TextAlign.end;
                                columnName = columnName.replaceAll('>', '');
                               else 
                                align = TextAlign.center;
                              

                              return DataColumn(
                                  label: Text(
                                columnName,
                                textAlign: align,
                              ));
                            ).toList(),
                            rows: table.rowData.map<DataRow>((e) 
                              return DataRow(
                                  cells: e
                                      .map<DataCell>((e) => DataCell(Text(e)))
                                      .toList());
                            ).toList(),
                          ),
                        );
                      );
                
              ,
            )));
  

【讨论】:

谢谢你的灵魂。这真的很有帮助。通过一些修改,我能够实现结果。但是出现的一个问题是所有列的标题都重复了。我有什么问题吗 您能否再分享一些结构化虚拟 json 数据的示例,这将有助于我理解......如何提取数据以及哪个小部件适合该数据。 嗨@android_id我已经修改了第2步。请查看 请分享图片,我会努力整理的 让我们continue this discussion in chat.【参考方案2】:

使用 createTable() & 给它列表 & 对象必须有 .tojson() 方法

import 'package:flutter/material.dart';

// This class takes any list that its elements have .toJson method and return every list element as a table row
class TableController 
  static Widget createTable(List list) 
    List<TableRow> rows = [];
    rows.add(_createTableHeader(list[0].toJson().keys));
    for (var item in list) 
      rows.add(TableRow(
        children: _createTableBody(item.toJson().values),
      ));
    
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: Table(border: TableBorder.all(), children: rows),
    );
  

  static TableRow _createTableHeader(Iterable<String> keys) 
    List<Widget> elements = [];
    for (String key in keys) 
      elements.add(Padding(
        padding: const EdgeInsets.all(4.0),
        child: Text(key.toString(), overflow: TextOverflow.ellipsis),
      ));
    
    return TableRow(
      children: elements,
    );
  

  static List<Widget> _createTableBody(Iterable values) 
    List<Widget> elements = [];
    for (var value in values) 
      elements.add(Padding(
        padding: const EdgeInsets.all(4.0),
        child: Text(value.toString(), overflow: TextOverflow.ellipsis),
      ));
    
    return elements;
  

像这样使用它:

class Employee 
      Employee(
        this.id,
        this.name,
        this.email,
      );
    
      int id;
      String name;
      String email;
    
      Map<String, dynamic> toJson() => 
            "id": id,
            "name": name,
            "email": email,
          ;
    
    
    final Employee emp = Employee(id: 1, name: 'name 1');
    final Employee emp1 = Employee(id: 2, name: 'name 2');
    final Employee emp2 = Employee(id: 3, name: 'name 3');
    final Employee emp3 = Employee(id: 4, name: 'name 4');
    final List<Employee> emps = [emp, emp2, emp1];

class TablePage extends StatelessWidget 
      @override
      Widget build(BuildContext context) 
        return Scaffold(
          body: Center(child: TableController.createTable(emps)),
        );
      
    

输出:

【讨论】:

【参考方案3】:

您正在尝试将 List 设置为具有 Widget 类型的属性:DataColumn 中的标签和 DataCell 中的子级。 List 不是 Widget 的子类型。这里可能需要 ListView。

【讨论】:

以上是关于在 Flutter 中动态显示数据表布局中的 JSON 数据的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Flutter 中使用动画更改行/列状态?

Flutter 中的动态闪屏

《Dart Flutter教程》

android 存在数据库中的动态图片,如何读取出来,显示在ImageView中

Flutter LayoutBuilder组件

如何在 Flutter 中显示 onclick 按钮动画布局?