Flutter

03. Fultter Datatable 사용

NaHyungMin 2022. 9. 7. 10:39

거래처 datatable을 만들고 싶음.

국내 사이트에선 정보가 없고, 해외 사이트에선 밑단 service가 아닌 screen에서 처리하는 샘플만 봄.

그래서 4시간 동안 서치하고 변경한 정보를 공유 차 올림.

pub

syncfusion_flutter_datagrid: ^20.2.46

 

Customers

import 'package:flutter/material.dart';
import 'package:simple/datagrid/customer_datagrid.dart';
import 'package:simple/model/customer/customer_model.dart';
import 'package:simple/services/customer/customer_service.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';

class Customers extends StatefulWidget {
  const Customers({Key? key}) : super(key: key);

  @override
  State<Customers> createState() => _CustomersState();
}

class _CustomersState extends State<Customers> {
  late final CustomerService customerService;
  late final CustomerDatagrid customerDatagrid;

  @override
  Widget build(BuildContext context) {
    //https://stackoverflow.com/questions/49986303/flutter-how-to-add-a-header-row-to-a-listview
    //https://api.flutter.dev/flutter/material/DataTable-class.html
    //https://stackoverflow.com/questions/60644375/flutter-datatable-multiline-wrapping-and-centering
    //https://www.syncfusion.com/kb/12646/how-to-populate-flutter-datatable-sfdatagrid-with-json-api

    customerService = CustomerService(context);
    return Scaffold(
      body: FutureBuilder(
          future: generateCustomerList(),
          builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
            return _getData(snapshot);
          }),
    );
  }

  Future generateCustomerList() async {
    List<CustomerModel> customerModelList = await customerService.getCustomerList() as List<CustomerModel>;
    customerDatagrid = CustomerDatagrid(customerModelList);
    customerDatagrid.customerModelList = customerModelList;
  }

  Widget _getData(AsyncSnapshot<dynamic> snapshot) {
    return snapshot.connectionState == ConnectionState.done
        ? SfDataGrid(
        source: customerDatagrid,
        columns: customerDatagrid.getColumns())
        : const Center(
            child: CircularProgressIndicator(
            strokeWidth: 3,
          ),
      );
  }
}

 

CustomerService

import 'package:flutter/material.dart';
import 'package:simple/commons/text/text_information.dart';
import 'package:simple/model/customer/customer_model.dart';
import 'package:simple/model/http/http_header_model.dart';
import 'package:simple/utils/dialog/custom_dialog.dart';
import 'package:simple/utils/dialog/dialog_action.dart';

import 'package:simple/utils/http/http_request.dart';
import 'package:simple/utils/http/http_url.dart';

import 'package:simple/model/customer/customer_model_list.dart';

class CustomerService {
  final BuildContext context;

  CustomerService(this.context);

  void add(CustomerModel customerModel) {
    CustomDialog.confirm(context, title: '저장 확인', content: '입력한 정보로 거래처를 저장하시겠습니까?'
        , positive: DialogAction('확인', () => _add(customerModel))
        , negative: DialogAction('취소',  () => true));
  }

  bool _add(CustomerModel customerModel) {
    HttpHeaderModel httpHeaderModel = HttpHeaderModel();
    httpHeaderModel.transactionNumber = "1000";
    final result = HttpRequest.fetchPost<CustomerModel>(HttpUrl.customerAdd, httpHeaderModel, customerModel);

    result.then((value) => {
      if(value == null) {
        CustomDialog.confirm(context, title: '거래처 등록', content: TextInformation.serverConnectionFailed, positive: DialogAction('확인', () => true))
      } else if(!value.status) {
        CustomDialog.confirm(context, title: '거래처 등록', content: '거래처 등록에 실패하였습니다. 사유 : ${value?.error.errorMessage}', positive: DialogAction('확인', () => true))
      } else {
        if(value.status) {
          CustomDialog.confirm(context, title: '거래처 등록', content: '거래처 등록에 완료되었습니다.', positive: DialogAction('확인', () => true)),
        }
      }
    });

    return true;
  }

  Future getCustomerList() async {
    HttpHeaderModel httpHeaderModel = HttpHeaderModel();
    httpHeaderModel.transactionNumber = "1000";
    final result = HttpRequest.fetchPostNoBody(HttpUrl.customerList, httpHeaderModel);
    CustomerModelList customerModelList = CustomerModelList(customerModelList: <CustomerModel>[]);

    var bb = await result.then((value) => {
      if(value == null) {
        CustomDialog.confirm(context, title: '거래처 리스트', content: TextInformation.serverConnectionFailed, positive: DialogAction('확인', () => true))
      } else if(!value.status) {
        CustomDialog.confirm(context, title: '거래처 리스트', content: '거래처 리스트를 불러오는데 실패했습니다. 사유 : ${value?.error.errorMessage}', positive: DialogAction('확인', () => true))
      } else {
        if(value.status) {
          customerModelList = CustomerModelList.fromJson(value.data),
        }
      }
    });

    return customerModelList.customerModelList;
  }

  bool _addConfirmDialog() {
    return true;
  }
}

 

CustomerDatagrid

 

import 'package:flutter/material.dart';
import 'package:simple/model/customer/customer_model.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
//import 'package:intl/intl.dart';

class CustomerDatagrid extends DataGridSource {
//https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid-class.html
//https://pub.dev/packages/syncfusion_flutter_datagrid
//https://help.syncfusion.com/flutter/datagrid/getting-started
  CustomerDatagrid(this.customerModelList) {
    buildDataGridRow();
  }

  List<DataGridRow> dataGridRows = [];
  List<CustomerModel> customerModelList = [];

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

  void buildDataGridRow() {
    dataGridRows = customerModelList.map<DataGridRow>((dataGridRow) {
      return DataGridRow(cells: [
        DataGridCell<String>(columnName: 'name', value: dataGridRow.name),
        DataGridCell<String>(
            columnName: 'number', value: dataGridRow.number),
        DataGridCell<String>(
            columnName: 'registrationNumber', value: dataGridRow.registrationNumber),
        DataGridCell<String>(
            columnName: 'conditions', value: dataGridRow.conditions),
        DataGridCell<String>(columnName: 'type', value: dataGridRow.type),
      ]);
    }).toList(growable: false);
  }

  @override
  DataGridRowAdapter buildRow(DataGridRow row) {
    return DataGridRowAdapter(cells: [
      Container(
        alignment: Alignment.center,
        padding: const EdgeInsets.all(8.0),
        child: Text(
          row.getCells()[0].value.toString(),
          overflow: TextOverflow.ellipsis,
        ),
      ),
      Container(
        alignment: Alignment.center,
        padding: const EdgeInsets.all(8.0),
        child: Text(
          row.getCells()[1].value,
          overflow: TextOverflow.ellipsis,
        ),
      ),
      Container(
        alignment: Alignment.center,
        padding: const EdgeInsets.all(8.0),
        child: Text(
          row.getCells()[2].value.toString(),
          overflow: TextOverflow.ellipsis,
        ),
      ),
      Container(
        alignment: Alignment.center,
        padding: const EdgeInsets.all(8.0),
        child: Text(
          //DateFormat('MM/dd/yyyy').format(row.getCells()[3].value).toString(),
          row.getCells()[3].value.toString(),
          overflow: TextOverflow.ellipsis,
        ),
      ),
      Container(
        alignment: Alignment.center,
        padding: const EdgeInsets.all(8.0),
        child: Text(
          row.getCells()[4].value.toString(),
          overflow: TextOverflow.ellipsis,
        ),
      ),
    ]);
  }

  List<GridColumn> getColumns() {
    return <GridColumn>[
      GridColumn(
          columnName: 'name',
          label: Container(
              padding: const EdgeInsets.all(16.0),
              alignment: Alignment.center,
              child: const Text('name',))),
      GridColumn(
          columnName: 'number',
          label: Container(
              padding: const EdgeInsets.all(16.0),
              alignment: Alignment.center,
              child: const Text('number'))),
      GridColumn(
          columnName: 'registrationNumber',
          width: 120,
          label: Container(
              padding: const EdgeInsets.all(16.0),
              alignment: Alignment.center,
              child: const Text('registrationNumber'))),
      GridColumn(
          columnName: 'conditions',
          label: Container(
              padding: const EdgeInsets.all(16.0),
              alignment: Alignment.center,
              child: const Text('conditions'))),
      GridColumn(
          columnName: 'type',
          label: Container(
              padding: const EdgeInsets.all(16.0),
              alignment: Alignment.center,
              child: const Text('type'))),
    ];
  }
}

 

 

테스트 용으로 서버에서 받아온 데이터라 정상적인 데이터 입력 시 매핑됨.

 

* 매핑 변경

@override
DataGridRowAdapter buildRow(DataGridRow row) {
  return DataGridRowAdapter(
      cells: row.getCells().map<Widget>((dataGridCell) {
        return Container(
            alignment: (dataGridCell.columnName == 'id' ||
                dataGridCell.columnName == 'salary')
                ? Alignment.centerRight
                : Alignment.centerLeft,
            padding: const EdgeInsets.symmetric(horizontal: 16.0),
            child: Text(
              dataGridCell.value.toString(),
              overflow: TextOverflow.ellipsis,
            ));
      }).toList());
}

 

List<GridColumn> getColumns() {
  return <GridColumn>[
    customGridColumn.getCustomGridColumn("name", "상호", alignment: Alignment.center),
    customGridColumn.getCustomGridColumn("number", "사업자번호", alignment: Alignment.center),
    customGridColumn.getCustomGridColumn("registrationNumber", "법인 등록번호", alignment: Alignment.center, width: 150),
    customGridColumn.getCustomGridColumn("conditions", "업태"),
    customGridColumn.getCustomGridColumn("ceoName", "종목"),
    customGridColumn.getCustomGridColumn("conditions", "대표자 성명"),
    customGridColumn.getCustomGridColumn("address", "회사 주소"),
    customGridColumn.getCustomGridColumn("phoneNumber", "전화번호", width: 120),
    customGridColumn.getCustomGridColumn("faxNumber", "팩스번호"),
    customGridColumn.getCustomGridColumn("cellNumber", "휴대폰"),
    customGridColumn.getCustomGridColumn("email", "이메일"),
    customGridColumn.getCustomGridColumn("bankName", "은행명"),
    customGridColumn.getCustomGridColumn("bankOwnerName", "예금주"),
    customGridColumn.getCustomGridColumn("bankAccountNumber", "계좌번호"),
  ];
}

 


class CustomGridColumn {
  //https://flutterrdart.com/dart-optional-default-parameters-function/
  GridColumn getCustomGridColumn(String columnName, String text, { Alignment alignment = Alignment.center, int width = -1 }) {
    double? columnWidth = width > 0 ? width as double : null;

    if(columnWidth != null) {
      return _getCustomGridColumnWidth(columnName, text, alignment, columnWidth);
    } else {
      return GridColumn(
          columnName: columnName,
          label: Container(
            padding: const EdgeInsets.all(16.0),
            alignment: alignment,
            child: Text(text),
          )
      );
    }
  }

  GridColumn _getCustomGridColumnWidth(String columnName, String text, Alignment alignment, double width) {
    return GridColumn(
        columnName: columnName,
        width: width,
        label: Container(
          padding: const EdgeInsets.all(16.0),
          alignment: alignment,
          child: Text(text),
        )
    );
  }
}