A Horizontal Data Table with A Fixed Column on Left Handside

horizontal_data_table .A Flutter Widget that create a horizontal table with fixed column on left hand side.

Installation

This package is starting to support sound null-safety. Although the package is migrated manually and tested with each functions, please feel free to file issue on GitHub if there is any problem on the integration/migration. The following is the guide for installation with different dart sdk and flutter version.

minium dart sdkflutter version (stable)package version
<2.12.0<2.0.1v2.5.1
<2.12.0=2.0.1v2.5.2
>=2.12.0 (enabled null-safety)=2.0.1latest

Usage

This shows Widget's full customizations:

HorizontalDataTable(
      {
      required this.leftHandSideColumnWidth,
      required this.rightHandSideColumnWidth,
      this.tableHeight,
      this.isFixedHeader = false,
      this.headerWidgets,
      this.leftSideItemBuilder,
      this.rightSideItemBuilder,
      this.itemCount = 0,
      this.leftSideChildren,
      this.rightSideChildren,
      this.rowSeparatorWidget = const Divider(
        color: Colors.transparent,
        height: 0.0,
        thickness: 0.0,
      ),
      this.elevation = 3.0,
      this.elevationColor = Colors.black54,
      this.leftHandSideColBackgroundColor = Colors.white,
      this.rightHandSideColBackgroundColor = Colors.white,
      this.horizontalScrollController,
      this.verticalScrollController,
      this.verticalScrollbarStyle,
      this.horizontalScrollbarStyle,
      this.enablePullToRefresh = false,
      this.refreshIndicatorHeight = 60.0,
      this.refreshIndicator: const WaterDropHeader(),
      this.onRefresh: (){},
      this.htdRefreshController: _hdtRefreshController,             
      this.scrollPhysics,
      this.horizontalScrollPhysics,
      }
     )
      
  1. Left side column(leftHandSideColumnWidth) and right side maximum scrollable area width(rightHandSideColumnWidth) are required to input.
  2. tableHeight is for manually set the table widget's height. The table widget height is using the smaller value of tableHeight and available height. Default is set to null, which is equal to using available height.
  3. isFixedHeader is to define whether use fixed top row header. If true, headerWidgets is required. Default is false.
  4. This widget allow set children in two ways, a. Directly add list of child widget (leftSideChildren and rightSideChildren) b. (Recommended) Using index builder to assign each row's widget. itemCount is required to count the number of row.
  5. rowSeparatorWidget is to add Divider of each Row. Default is turned off.
  6. elevation is the shadow between the header row and the left column when scroll start. Default set to 5.0. If want to disable the shadow, please set to 0.0.
  7. elevationColor is for changing shadow color. This should be useful when using dark table background.
  8. added leftHandSideColBackgroundColor and rightHandSideColBackgroundColor for setting the default background of the back of table. Default is set to white following the Material widget.
  9. added horizontalScrollController and verticalScrollController allow maunally jump to certain offset position. Please aware that if you have enabled the pull to refresh function, the jump to action may conflict with the pull to refresh action.
  10. verticalScrollbarStyle and horizontalScrollbarStyle are a ScrollbarStyle class object which allows customizing isAlwaysShown, thumbColor, thickness and radius. Default is using system style scrollbar.
  11. enablePullToRefresh is to define whether enable the pull-to-refresh function. Default is setting to false. Detail you may reference to the Pull to Refresh section.
  12. scrollPhysics and horizontalScrollPhysics are to set scroll physics of the data table. Please aware scrollPhysics may causing conflict when enabling pull-to-refresh feature.

Pull to Refresh

The pull to refresh action is impletemented based on the 'pull-to-refresh' package code. Currently only part of the function is available.

HorizontalDataTable(
      {
        ...
      this.enablePullToRefresh = true,
      this.refreshIndicator: const WaterDropHeader(),
      this.onRefresh: _onRefresh,
      this.htdRefreshController: _hdtRefreshController,
      }
     )
      

refreshIndicator is the header widget when pull to refresh. Supported refreshIndicator:

  1. ClassicHeader
  2. WaterDropHeader
  3. CustomHeader
  4. BezierHeader

refreshIndicatorHeight is the height of the refreshIndicator. Default is set to 60.

onRefresh is the callback from the refresh action.

htdRefreshController is the wrapper controller for returning the refresh result. This is the example on how to use onRefresh and htdRefreshController.

All of this 4 params are required when enablePullToRefresh is set to true.

Example

import 'package:flutter/material.dart';
import 'package:horizontal_data_table/horizontal_data_table.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  HDTRefreshController _hdtRefreshController = HDTRefreshController();

  static const int sortName = 0;
  static const int sortStatus = 1;
  bool isAscending = true;
  int sortType = sortName;

  @override
  void initState() {
    user.initData(100);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: _getBodyWidget(),
    );
  }

  Widget _getBodyWidget() {
    return Container(
      child: HorizontalDataTable(
        leftHandSideColumnWidth: 100,
        rightHandSideColumnWidth: 600,
        isFixedHeader: true,
        headerWidgets: _getTitleWidget(),
        leftSideItemBuilder: _generateFirstColumnRow,
        rightSideItemBuilder: _generateRightHandSideColumnRow,
        itemCount: user.userInfo.length,
        rowSeparatorWidget: const Divider(
          color: Colors.black54,
          height: 1.0,
          thickness: 0.0,
        ),
        leftHandSideColBackgroundColor: Color(0xFFFFFFFF),
        rightHandSideColBackgroundColor: Color(0xFFFFFFFF),
        verticalScrollbarStyle: const ScrollbarStyle(
          isAlwaysShown: true,
          thickness: 4.0,
          radius: Radius.circular(5.0),
        ),
        horizontalScrollbarStyle: const ScrollbarStyle(
          isAlwaysShown: true,
          thickness: 4.0,
          radius: Radius.circular(5.0),
        ),
        enablePullToRefresh: true,
        refreshIndicator: const WaterDropHeader(),
        refreshIndicatorHeight: 60,
        onRefresh: () async {
          //Do sth
          await Future.delayed(const Duration(milliseconds: 500));
          _hdtRefreshController.refreshCompleted();
        },
        htdRefreshController: _hdtRefreshController,
      ),
      height: MediaQuery.of(context).size.height,
    );
  }

  List<Widget> _getTitleWidget() {
    return [
      TextButton(
        style: TextButton.styleFrom(
          padding: EdgeInsets.zero,
        ),
        child: _getTitleItemWidget(
            'Name' + (sortType == sortName ? (isAscending ? '↓' : '↑') : ''),
            100),
        onPressed: () {
          sortType = sortName;
          isAscending = !isAscending;
          user.sortName(isAscending);
          setState(() {});
        },
      ),
      TextButton(
        style: TextButton.styleFrom(
          padding: EdgeInsets.zero,
        ),
        child: _getTitleItemWidget(
            'Status' +
                (sortType == sortStatus ? (isAscending ? '↓' : '↑') : ''),
            100),
        onPressed: () {
          sortType = sortStatus;
          isAscending = !isAscending;
          user.sortStatus(isAscending);
          setState(() {});
        },
      ),
      _getTitleItemWidget('Phone', 200),
      _getTitleItemWidget('Register', 100),
      _getTitleItemWidget('Termination', 200),
    ];
  }

  Widget _getTitleItemWidget(String label, double width) {
    return Container(
      child: Text(label, style: TextStyle(fontWeight: FontWeight.bold)),
      width: width,
      height: 56,
      padding: EdgeInsets.fromLTRB(5, 0, 0, 0),
      alignment: Alignment.centerLeft,
    );
  }

  Widget _generateFirstColumnRow(BuildContext context, int index) {
    return Container(
      child: Text(user.userInfo[index].name),
      width: 100,
      height: 52,
      padding: EdgeInsets.fromLTRB(5, 0, 0, 0),
      alignment: Alignment.centerLeft,
    );
  }

  Widget _generateRightHandSideColumnRow(BuildContext context, int index) {
    return Row(
      children: <Widget>[
        Container(
          child: Row(
            children: <Widget>[
              Icon(
                  user.userInfo[index].status
                      ? Icons.notifications_off
                      : Icons.notifications_active,
                  color:
                      user.userInfo[index].status ? Colors.red : Colors.green),
              Text(user.userInfo[index].status ? 'Disabled' : 'Active')
            ],
          ),
          width: 100,
          height: 52,
          padding: EdgeInsets.fromLTRB(5, 0, 0, 0),
          alignment: Alignment.centerLeft,
        ),
        Container(
          child: Text(user.userInfo[index].phone),
          width: 200,
          height: 52,
          padding: EdgeInsets.fromLTRB(5, 0, 0, 0),
          alignment: Alignment.centerLeft,
        ),
        Container(
          child: Text(user.userInfo[index].registerDate),
          width: 100,
          height: 52,
          padding: EdgeInsets.fromLTRB(5, 0, 0, 0),
          alignment: Alignment.centerLeft,
        ),
        Container(
          child: Text(user.userInfo[index].terminationDate),
          width: 200,
          height: 52,
          padding: EdgeInsets.fromLTRB(5, 0, 0, 0),
          alignment: Alignment.centerLeft,
        ),
      ],
    );
  }
}

User user = User();

class User {
  List<UserInfo> userInfo = [];

  void initData(int size) {
    for (int i = 0; i < size; i++) {
      userInfo.add(UserInfo(
          "User_$i", i % 3 == 0, '+001 9999 9999', '2019-01-01', 'N/A'));
    }
  }

  ///
  /// Single sort, sort Name's id
  void sortName(bool isAscending) {
    userInfo.sort((a, b) {
      int aId = int.tryParse(a.name.replaceFirst('User_', '')) ?? 0;
      int bId = int.tryParse(b.name.replaceFirst('User_', '')) ?? 0;
      return (aId - bId) * (isAscending ? 1 : -1);
    });
  }

  ///
  /// sort with Status and Name as the 2nd Sort
  void sortStatus(bool isAscending) {
    userInfo.sort((a, b) {
      if (a.status == b.status) {
        int aId = int.tryParse(a.name.replaceFirst('User_', '')) ?? 0;
        int bId = int.tryParse(b.name.replaceFirst('User_', '')) ?? 0;
        return (aId - bId);
      } else if (a.status) {
        return isAscending ? 1 : -1;
      } else {
        return isAscending ? -1 : 1;
      }
    });
  }
}

class UserInfo {
  String name;
  bool status;
  String phone;
  String registerDate;
  String terminationDate;

  UserInfo(this.name, this.status, this.phone, this.registerDate,
      this.terminationDate);
}

Issues Report and Feature Request

Thank you for your reporting and suggestion making this package more complete!

Since many developers get in touch with this package in different places (pub.dev, GitHub, and others website recommandation), I have received your voice regarding to feature request, issue report and question via different channels.

To avoid missing of the messages, I have created the issue templates on GitHub which allow our conversations with ease, especially some discussions are complex when they need to talk with the sample code.

License

MIT

 void _onRefresh() async {
   //do some network call and get the response

   if(isError){
     //call this when it is an error case
     _hdtRefreshController.refreshFailed();
   }else{
     //call this when it is a success case
     _hdtRefreshController.refreshCompleted();
   }      
 },

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add horizontal_data_table

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:  horizontal_data_table: ^3.4.3

Alternatively, your editor might support or flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:horizontal_data_table/horizontal_data_table.dart'; 

example/lib/main.dart

import 'package:flutter/material.dart';import 'package:horizontal_data_table/horizontal_data_table.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget {  // This widget is the root of your application.  @override  Widget build(BuildContext context) {    return MaterialApp(      title: 'Flutter Demo',      theme: ThemeData(        primarySwatch: Colors.blue,      ),      home: MyHomePage(title: 'Flutter Demo Home Page'),    );  }}class MyHomePage extends StatefulWidget {  MyHomePage({Key? key, required this.title}) : super(key: key);  final String title;  @override  _MyHomePageState createState() => _MyHomePageState();}class _MyHomePageState extends State<MyHomePage> {  HDTRefreshController _hdtRefreshController = HDTRefreshController();  static const int sortName = 0;  static const int sortStatus = 1;  bool isAscending = true;  int sortType = sortName;  @override  void initState() {    user.initData(100);    super.initState();  }  @override  Widget build(BuildContext context) {    return Scaffold(      appBar: AppBar(        title: Text(widget.title),      ),      body: _getBodyWidget(),    );  }  Widget _getBodyWidget() {    return Container(      child: HorizontalDataTable(        leftHandSideColumnWidth: 100,        rightHandSideColumnWidth: 600,        isFixedHeader: true,        headerWidgets: _getTitleWidget(),        leftSideItemBuilder: _generateFirstColumnRow,        rightSideItemBuilder: _generateRightHandSideColumnRow,        itemCount: user.userInfo.length,        rowSeparatorWidget: const Divider(          color: Colors.black54,          height: 1.0,          thickness: 0.0,        ),        leftHandSideColBackgroundColor: Color(0xFFFFFFFF),        rightHandSideColBackgroundColor: Color(0xFFFFFFFF),        verticalScrollbarStyle: const ScrollbarStyle(          thumbColor: Colors.yellow,          isAlwaysShown: true,          thickness: 4.0,          radius: Radius.circular(5.0),        ),        horizontalScrollbarStyle: const ScrollbarStyle(          thumbColor: Colors.red,          isAlwaysShown: true,          thickness: 4.0,          radius: Radius.circular(5.0),        ),        enablePullToRefresh: true,        refreshIndicator: const WaterDropHeader(),        refreshIndicatorHeight: 60,        onRefresh: () async {          //Do sth          await Future.delayed(const Duration(milliseconds: 500));          _hdtRefreshController.refreshCompleted();        },        htdRefreshController: _hdtRefreshController,      ),      height: MediaQuery.of(context).size.height,    );  }  List<Widget> _getTitleWidget() {    return [      TextButton(        style: TextButton.styleFrom(          padding: EdgeInsets.zero,        ),        child: _getTitleItemWidget(            'Name' + (sortType == sortName ? (isAscending ? '↓' : '↑') : ''),            100),        onPressed: () {          sortType = sortName;          isAscending = !isAscending;          user.sortName(isAscending);          setState(() {});        },      ),      TextButton(        style: TextButton.styleFrom(          padding: EdgeInsets.zero,        ),        child: _getTitleItemWidget(            'Status' +                (sortType == sortStatus ? (isAscending ? '↓' : '↑') : ''),            100),        onPressed: () {          sortType = sortStatus;          isAscending = !isAscending;          user.sortStatus(isAscending);          setState(() {});        },      ),      _getTitleItemWidget('Phone', 200),      _getTitleItemWidget('Register', 100),      _getTitleItemWidget('Termination', 200),    ];  }  Widget _getTitleItemWidget(String label, double width) {    return Container(      child: Text(label, style: TextStyle(fontWeight: FontWeight.bold)),      width: width,      height: 56,      padding: EdgeInsets.fromLTRB(5, 0, 0, 0),      alignment: Alignment.centerLeft,    );  }  Widget _generateFirstColumnRow(BuildContext context, int index) {    return Container(      child: Text(user.userInfo[index].name),      width: 100,      height: 52,      padding: EdgeInsets.fromLTRB(5, 0, 0, 0),      alignment: Alignment.centerLeft,    );  }  Widget _generateRightHandSideColumnRow(BuildContext context, int index) {    return Row(      children: <Widget>[        Container(          child: Row(            children: <Widget>[              Icon(                  user.userInfo[index].status                      ? Icons.notifications_off                      : Icons.notifications_active,                  color:                      user.userInfo[index].status ? Colors.red : Colors.green),              Text(user.userInfo[index].status ? 'Disabled' : 'Active')            ],          ),          width: 100,          height: 52,          padding: EdgeInsets.fromLTRB(5, 0, 0, 0),          alignment: Alignment.centerLeft,        ),        Container(          child: Text(user.userInfo[index].phone),          width: 200,          height: 52,          padding: EdgeInsets.fromLTRB(5, 0, 0, 0),          alignment: Alignment.centerLeft,        ),        Container(          child: Text(user.userInfo[index].registerDate),          width: 100,          height: 52,          padding: EdgeInsets.fromLTRB(5, 0, 0, 0),          alignment: Alignment.centerLeft,        ),        Container(          child: Text(user.userInfo[index].terminationDate),          width: 200,          height: 52,          padding: EdgeInsets.fromLTRB(5, 0, 0, 0),          alignment: Alignment.centerLeft,        ),      ],    );  }}User user = User();class User {  List<UserInfo> userInfo = [];  void initData(int size) {    for (int i = 0; i < size; i++) {      userInfo.add(UserInfo(          "User_$i", i % 3 == 0, '+001 9999 9999', '2019-01-01', 'N/A'));    }  }  ///  /// Single sort, sort Name's id  void sortName(bool isAscending) {    userInfo.sort((a, b) {      int aId = int.tryParse(a.name.replaceFirst('User_', '')) ?? 0;      int bId = int.tryParse(b.name.replaceFirst('User_', '')) ?? 0;      return (aId - bId) * (isAscending ? 1 : -1);    });  }  ///  /// sort with Status and Name as the 2nd Sort  void sortStatus(bool isAscending) {    userInfo.sort((a, b) {      if (a.status == b.status) {        int aId = int.tryParse(a.name.replaceFirst('User_', '')) ?? 0;        int bId = int.tryParse(b.name.replaceFirst('User_', '')) ?? 0;        return (aId - bId);      } else if (a.status) {        return isAscending ? 1 : -1;      } else {        return isAscending ? -1 : 1;      }    });  }}class UserInfo {  String name;  bool status;  String phone;  String registerDate;  String terminationDate;  UserInfo(this.name, this.status, this.phone, this.registerDate,      this.terminationDate);}

Download Details:

Author: MayLau-CbL

Source Code: https://github.com/MayLau-CbL/flutter_horizontal_data_table

#table  #horizontal  #flutter  #datatable 

What is GEEK

Buddha Community

A Horizontal Data Table with A Fixed Column on Left Handside
Siphiwe  Nair

Siphiwe Nair

1620466520

Your Data Architecture: Simple Best Practices for Your Data Strategy

If you accumulate data on which you base your decision-making as an organization, you should probably think about your data architecture and possible best practices.

If you accumulate data on which you base your decision-making as an organization, you most probably need to think about your data architecture and consider possible best practices. Gaining a competitive edge, remaining customer-centric to the greatest extent possible, and streamlining processes to get on-the-button outcomes can all be traced back to an organization’s capacity to build a future-ready data architecture.

In what follows, we offer a short overview of the overarching capabilities of data architecture. These include user-centricity, elasticity, robustness, and the capacity to ensure the seamless flow of data at all times. Added to these are automation enablement, plus security and data governance considerations. These points from our checklist for what we perceive to be an anticipatory analytics ecosystem.

#big data #data science #big data analytics #data analysis #data architecture #data transformation #data platform #data strategy #cloud data platform #data acquisition

Gerhard  Brink

Gerhard Brink

1620629020

Getting Started With Data Lakes

Frameworks for Efficient Enterprise Analytics

The opportunities big data offers also come with very real challenges that many organizations are facing today. Often, it’s finding the most cost-effective, scalable way to store and process boundless volumes of data in multiple formats that come from a growing number of sources. Then organizations need the analytical capabilities and flexibility to turn this data into insights that can meet their specific business objectives.

This Refcard dives into how a data lake helps tackle these challenges at both ends — from its enhanced architecture that’s designed for efficient data ingestion, storage, and management to its advanced analytics functionality and performance flexibility. You’ll also explore key benefits and common use cases.

Introduction

As technology continues to evolve with new data sources, such as IoT sensors and social media churning out large volumes of data, there has never been a better time to discuss the possibilities and challenges of managing such data for varying analytical insights. In this Refcard, we dig deep into how data lakes solve the problem of storing and processing enormous amounts of data. While doing so, we also explore the benefits of data lakes, their use cases, and how they differ from data warehouses (DWHs).


This is a preview of the Getting Started With Data Lakes Refcard. To read the entire Refcard, please download the PDF from the link above.

#big data #data analytics #data analysis #business analytics #data warehouse #data storage #data lake #data lake architecture #data lake governance #data lake management

Cyrus  Kreiger

Cyrus Kreiger

1618039260

How Has COVID-19 Impacted Data Science?

The COVID-19 pandemic disrupted supply chains and brought economies around the world to a standstill. In turn, businesses need access to accurate, timely data more than ever before. As a result, the demand for data analytics is skyrocketing as businesses try to navigate an uncertain future. However, the sudden surge in demand comes with its own set of challenges.

Here is how the COVID-19 pandemic is affecting the data industry and how enterprises can prepare for the data challenges to come in 2021 and beyond.

#big data #data #data analysis #data security #data integration #etl #data warehouse #data breach #elt

Macey  Kling

Macey Kling

1597579680

Applications Of Data Science On 3D Imagery Data

CVDC 2020, the Computer Vision conference of the year, is scheduled for 13th and 14th of August to bring together the leading experts on Computer Vision from around the world. Organised by the Association of Data Scientists (ADaSCi), the premier global professional body of data science and machine learning professionals, it is a first-of-its-kind virtual conference on Computer Vision.

The second day of the conference started with quite an informative talk on the current pandemic situation. Speaking of talks, the second session “Application of Data Science Algorithms on 3D Imagery Data” was presented by Ramana M, who is the Principal Data Scientist in Analytics at Cyient Ltd.

Ramana talked about one of the most important assets of organisations, data and how the digital world is moving from using 2D data to 3D data for highly accurate information along with realistic user experiences.

The agenda of the talk included an introduction to 3D data, its applications and case studies, 3D data alignment, 3D data for object detection and two general case studies, which are-

  • Industrial metrology for quality assurance.
  • 3d object detection and its volumetric analysis.

This talk discussed the recent advances in 3D data processing, feature extraction methods, object type detection, object segmentation, and object measurements in different body cross-sections. It also covered the 3D imagery concepts, the various algorithms for faster data processing on the GPU environment, and the application of deep learning techniques for object detection and segmentation.

#developers corner #3d data #3d data alignment #applications of data science on 3d imagery data #computer vision #cvdc 2020 #deep learning techniques for 3d data #mesh data #point cloud data #uav data

Uriah  Dietrich

Uriah Dietrich

1618457700

What Is ETLT? Merging the Best of ETL and ELT Into a Single ETLT Data Integration Strategy

Data integration solutions typically advocate that one approach – either ETL or ELT – is better than the other. In reality, both ETL (extract, transform, load) and ELT (extract, load, transform) serve indispensable roles in the data integration space:

  • ETL is valuable when it comes to data quality, data security, and data compliance. It can also save money on data warehousing costs. However, ETL is slow when ingesting unstructured data, and it can lack flexibility.
  • ELT is fast when ingesting large amounts of raw, unstructured data. It also brings flexibility to your data integration and data analytics strategies. However, ELT sacrifices data quality, security, and compliance in many cases.

Because ETL and ELT present different strengths and weaknesses, many organizations are using a hybrid “ETLT” approach to get the best of both worlds. In this guide, we’ll help you understand the “why, what, and how” of ETLT, so you can determine if it’s right for your use-case.

#data science #data #data security #data integration #etl #data warehouse #data breach #elt #bid data