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

Overview

horizontal_data_table

pub package issues GitHub Page

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 sdk flutter version (stable) package version
<2.12.0 <2.0.1 v2.5.1
<2.12.0 =2.0.1 v2.5.2
>=2.12.0 (enabled null-safety) =2.0.1 latest

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,
      }
     )
      
  1. refreshIndicator is the header widget when pull to refresh. Supported refreshIndicator:

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

    Basically single level header with a certain height while refreshing. For the on-top header is currently not supported. Since refreshIndicator is a Widget type field, you may customize yourself on the header, but you must set the height of the header. The detail usage you may reference to the pull-to-refresh package.

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

  3. onRefresh is the callback from the refresh action.

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

    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();
      }      
    },
    

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
   
     {
  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
    
      _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: 
     
      [
        Container(
          child: Row(
            children: 
      
       [
              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 = []; 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

Comments
  • [Bug for v4.1.2] SpringDescription undefinded class

    [Bug for v4.1.2] SpringDescription undefinded class

    Describe the bug Latest 4.1.2 in pub.dev analysis is showing the SpringDescription cannot be definded. I have tested on my local env with example project have not problem with it and running flutter analyze but show nothing. Since it only show the first 2 issues on pub.dev only, I can only wait for their update on the flutter analyze to get further information. If you get any further information about this issue, please feel free to leave it here to let everyone notice. Thank you!

    螢幕截圖 2022-08-31 下午6 37 56

    Platform All

    bug 
    opened by MayLau-CbL 8
  • With `PullToRefresh` enabled , if I use `CustomHeader`, 刷新中 和 刷新完成 时,第一列和其他列的行不同步

    With `PullToRefresh` enabled , if I use `CustomHeader`, 刷新中 和 刷新完成 时,第一列和其他列的行不同步

    demo

    20210604_161819

    code

    import 'package:flutter/cupertino.dart';
    import 'package:flutter/material.dart';
    import 'package:horizontal_data_table/horizontal_data_table.dart';
    import 'package:horizontal_data_table/refresh/pull_to_refresh/src/smart_refresher.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(20);
        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: 0.0,
              radius: Radius.circular(5.0),
            ),
            horizontalScrollbarStyle: const ScrollbarStyle(
              thumbColor: Colors.red,
              isAlwaysShown: true,
              thickness: 0.0,
              radius: Radius.circular(5.0),
            ),
            enablePullToRefresh: true,
            refreshIndicator:
                /*
            const WaterDropHeader(),
            */
                CustomHeader(
              builder: (context, mode) {
                Widget body = Text("");
                if (mode == RefreshStatus.idle) {
                  body = Text("pull down refresh");
                } else if (mode == RefreshStatus.refreshing) {
                  body = CupertinoActivityIndicator();
                } else if (mode == RefreshStatus.canRefresh) {
                  body = Text("release to refresh");
                } else if (mode == RefreshStatus.completed) {
                  body = Text("refreshCompleted!");
                }
                return Container(
                  height: 60.0,
                  child: Center(
                    child: body,
                  ),
                );
              },
            ),
            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);
    }
    
    bug 
    opened by yingshaoxo 7
  • (childView.primary ? PrimaryScrollController.of(context) : null);

    (childView.primary ? PrimaryScrollController.of(context) : null);

    Describe the bug Description of what the bug is.

    ../flutter/.pub-cache/hosted/pub.dartlang.org/horizontal_data_table-4.1.1+1/lib/refresh/pull_to_refresh/src/smart_refresher.dart:412:24: Error: A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't. (childView.primary ? PrimaryScrollController.of(context) : null);

    Flutter 3.1.0-0.0.pre.1376 • channel master • https://github.com/flutter/flutter.git Framework • revision 3598f20002 (9 days ago) • 2022-06-26 18:19:04 -0400 Engine • revision ee56813c14 Tools • Dart 2.18.0 (build 2.18.0-228.0.dev) • DevTools 2.14.1

    Platform Please describe the affected platfrom(eg. IOS, Android, Web, Window, Mac, Linux)

    Screen Captures or Debug Log If applicable, add screenshots or debug log to help explain your problem.

    Additional context Add any other context about the problem here.

    bug 
    opened by prajwalcognerium 5
  • [Bug] Serveral Errors with smart_refresher:

    [Bug] Serveral Errors with smart_refresher: "SpringDescription"

    Hey :) after starting my app in flutter-debug-mode after a while, this error appears:

    /C:/Users/AppData/Local/flutter/.pub-cache/hosted/pub.dartlang.org/horizontal_data_table-4.1.2+2/lib/refresh/pull_to_refresh/src/smart_refresher.dart(828,9): error G5FE39F1E: Type 'SpringDescription' not found. [D:\software\build\windows\flutter\flutter_assemble.vcxproj] /C:/Users/AppData/Local/flutter/.pub-cache/hosted/pub.dartlang.org/horizontal_data_table-4.1.2+2/lib/refresh/pull_to_refresh/src/smart_refresher.dart(946,5): error G5FE39F1E: Type 'SpringDescription' not found. [D:\software\build\windows\flutter\flutter_assemble.vcxproj] /C:/Users/AppData/Local/flutter/.pub-cache/hosted/pub.dartlang.org/horizontal_data_table-4.1.2+2/lib/refresh/pull_to_refresh/src/internals/refresh_physics.dart(28,9): error G5FE39F1E: Type 'SpringDescription' not found. [D:\software\build\windows\flutter\flutter_assemble.vcxproj] /C:/Users/AppData/Local/flutter/.pub-cache/hosted/pub.dartlang.org/horizontal_data_table-4.1.2+2/lib/refresh/pull_to_refresh/src/smart_refresher.dart(903,37): error GF7CA4DBF: Couldn't find constructor 'SpringDescription'. [D:\software\build\windows\flutter\flutter_assemble.vcxproj] /C:/Users/AppData/Local/flutter/.pub-cache/hosted/pub.dartlang.org/horizontal_data_table-4.1.2+2/lib/refresh/pull_to_refresh/src/smart_refresher.dart(347,23): error GF7CA4DBF: Couldn't find constructor 'SpringDescription'. [D:\software\build\windows\flutter\flutter_assemble.vcxproj] /C:/Users/AppData/Local/flutter/.pub-cache/hosted/pub.dartlang.org/horizontal_data_table-4.1.2+2/lib/refresh/pull_to_refresh/src/smart_refresher.dart(828,9): error G104F1F23: 'SpringDescription' isn't a type. [D:\software\build\windows\flutter\flutter_assemble.vcxproj] /C:/Users/AppData/Local/flutter/.pub-cache/hosted/pub.dartlang.org/horizontal_data_table-4.1.2+2/lib/refresh/pull_to_refresh/src/smart_refresher.dart(946,5): error G104F1F23: 'SpringDescription' isn't a type. [D:\software\build\windows\flutter\flutter_assemble.vcxproj] /C:/Users/AppData/Local/flutter/.pub-cache/hosted/pub.dartlang.org/horizontal_data_table-4.1.2+2/lib/refresh/pull_to_refresh/src/internals/refresh_physics.dart(28,9): error G104F1F23: 'SpringDescription' isn't a type. [D:\software\build\windows\flutter\flutter_assemble.vcxproj]

    Do you know, how to handle this error?

    bug 
    opened by FloFerstl 4
  • [Question] Any way to change the background color?

    [Question] Any way to change the background color?

    Describe the Problem Can't change the background color of the vertical scrolling.

    Using the default bouncing physics, a white background appears when you scroll too far up or down. Is there any way to change this to a different color? I have a dark UI and the white looks awful when you scroll past, yet I would like to keep the bouncing physics.

    help wanted 
    opened by SwiftCODA 4
  • [Question]Set

    [Question]Set "BouncingScrollPhysics" to "scrollPhysics".

    Describe the Problem Please tell me about the setting of "scrollPhysics". "BouncingScrollPhysics" is set in "scrollPhysics". However, when scrolling the line, the positions of "leftSideItemBuilder" and "rightSideItemBuilder" are misaligned. "RightSideItemBuilder" returns to its initial position while scrolling "leftSideItemBuilder". Is there a way to link "leftSideItemBuilder" and "rightSideItemBuilder"?

    [1.Initial position] No01

    [2.Scrolling] No02

    [3.Stop scrolling] No03

    help wanted 
    opened by Yuki-Ut 4
  • isAlwaysShown was called on null

    isAlwaysShown was called on null

    Hi I try to workaround with the example in Readme. And I got error'isAlwaysShown' was called on null. As you can see in below image.

    image

    I use Mac with below version:

    • Flutter 1.22.6 • channel stable
    • Dart 2.10.5
    bug 
    opened by Kimhak-Loem 4
  • [Question]Are there any problems with the keyboard scrolling to the top when it is activated?

    [Question]Are there any problems with the keyboard scrolling to the top when it is activated?

    Are there any problems with the keyboard scrolling to the top when it is activated?

    HorizontalDataTable(
        // Expected behavior in previous versions
        // verticalScrollController: ref.read(appProvider.notifier).scrollController,
    
        // If I modify it this way, it scrolls to the top every time I open the keyboard
        onScrollControllerReady: (vertical, _) {
          ref.read(appProvider.notifier).scrollController = vertical;
        },
    );
    
    help wanted 
    opened by nrikiji 3
  • ExtraPadding before Header[Bug]

    ExtraPadding before Header[Bug]

    Describe the bug I am using horizontal_data_table: ^ 3.5.0. I am quite confused because I have not get to remove an Extra Padding that is putting the Widget just before displaying the Header (see Graph 1). A proof that this extra padding is specifically due to Horizontal_Data_Table, is that if I change this function to a simple text that says 'Hello' that padding stops appearing. How can I remove this padding?

    ExtraPadding - Graph 1

    The code I am using in Horizontal Data Table is as follows:

    StreamBuilder(
            stream: estanquesBloc.estanqueLoteStream,
            builder: (BuildContext context, AsyncSnapshot<List<LoteModel>> snapshot){
              if (snapshot.hasData) {
                loteList = snapshot.data;
                if (loteList!.isEmpty) return _imagenInicial(context);
                return HorizontalDataTable(
                  leftHandSideColumnWidth: _size.width*(0.13+0.045), 
                  rightHandSideColumnWidth: _size.width*(0.1*7+0.15),
                  isFixedHeader: true,
                  headerWidgets: _titulos(),
                  leftSideItemBuilder: (context, i) =>_crearItemsPrimeraColumna(context, loteList![i]),
                  rightSideItemBuilder: (context, i) =>_crearItemsSiguientesColumnas(context, loteList![i]),
                  itemCount: loteList!.length,
                  rowSeparatorWidget: Container(
                    height: 10.0,
                    color: Colors.grey[200],
                  ),
                  htdRefreshController: _hdtRefreshController,
                );
              } else if (snapshot.hasError) {
                return Text(snapshot.error.toString());
              } 
                return const Center (child: Image(image: AssetImage('assets/Aplians-fish-Preloader.gif'), height: 100.0,));
            }
        );
    

    If I change HorizontalDataTable by a Hello Text the result is as follows:

    No Extra Padding - Graph 2

    The code to demonstrate that the Padding is due to HorizontalDataTable Widget is as follows:

    StreamBuilder(
            stream: estanquesBloc.estanqueLoteStream,
            builder: (BuildContext context, AsyncSnapshot<List<LoteModel>> snapshot){
              if (snapshot.hasData) {
                loteList = snapshot.data;
                if (loteList!.isEmpty) return _imagenInicial(context);
                return Text('Hello');
              } else if (snapshot.hasError) {
                return Text(snapshot.error.toString());
              } 
                return const Center (child: Image(image: AssetImage('assets/Aplians-fish-Preloader.gif'), height: 100.0,));
            }
        );
    

    Platform I'm testing on IOS and Android

    Screen Captures or Debug Log It was included

    Additional context It was included

    bug 
    opened by dlondonog 3
  • Always show the scrollbar on the right hand size on the screen

    Always show the scrollbar on the right hand size on the screen

    On flutter web if the right side scrollbar will only show if the user scrolls all the way to the right side. If both the width and height dimensions are offscreen. This fix will always show both scrollbars on screen.

    To reproduce:

    1. Make a table with data that is too big for the screen both width and height
    2. Scroll the height of the table noticed the vertical scroll bar doesn't show.
    3. To see the vertical scroll bar scroll all the way to the right
    opened by igloo12 3
  • 表格内部有padding无法移除

    表格内部有padding无法移除

    test 表格固定了11行,然后也设置了固定11行的高度,但是未能完全展示表格,底部貌似有padding无法移除,如上述图片,代码如下:
     return Container(
          height: ((contentList.length + 1) * 46).toDouble(),
          padding: EdgeInsets.zero,
          child: HorizontalDataTable(
            leftHandSideColumnWidth: 100,
            rightHandSideColumnWidth: ((titleList.length - 1) * 100).toDouble(),
            isFixedHeader: true,
            headerWidgets: _getTitleWidget(titleList),
            leftSideItemBuilder: _generateFirstColumnRow,
            rightSideItemBuilder: _generateRightSideColumnRow,
            itemCount: contentList.length,
            rowSeparatorWidget: const Divider(
              color: Colors.transparent,
              height: 0.0,
              thickness: 0.0,
            ),
            leftHandSideColBackgroundColor: Colors.white,
            rightHandSideColBackgroundColor: Colors.white,
            enablePullToRefresh: false,
          ),
        );
    
    opened by evergreenlol 3
  • [Feature] Export to CSV

    [Feature] Export to CSV

    Describe the Feature A small icon or button that will let the user download a csv file of the data displayed by the view.

    Describe the Solution Not really sure how to go about it.

    enhancement 
    opened by pryshrm 1
  • I get an exception when I recall the request with more columns to add  [Question]

    I get an exception when I recall the request with more columns to add [Question]

    At some point in my app I recall the request -that builds the table columns and rows- with extra parameters so the table will have more width, the app works fine even with the exception but I hope to solve it.

    Important note : I'm trying to recall the request automatically after editing the sent parameters, if I change the parameters then recalled the request manually not automatically the exception won't be thrown!

    Exception : **The following assertion was thrown during a scheduler callback: The Scrollbar's ScrollController has no ScrollPosition attached.

    A Scrollbar cannot be painted without a ScrollPosition.

    The Scrollbar attempted to use the provided ScrollController. This ScrollController should be associated with the ScrollView that the Scrollbar is being applied to. When providing your own ScrollController, ensure both the Scrollbar and the Scrollable widget use the same one.**

    help wanted 
    opened by mhilalsh 1
  • Is there a way to change width of vertical line that separates first column?

    Is there a way to change width of vertical line that separates first column?

    Right now, the line showing the first column is frozen/sticky only appears when you scroll horizontally. Two questions.

    1. Is there a way to always have that line appear?
    2. Is there a way to customize (size and/or color) of this line?

    image

    help wanted 
    opened by ElixirMike 0
  • Scroll outer widget when reached top or bottom

    Scroll outer widget when reached top or bottom

    We have screen where multiple types of widgets are shown like table, pie chart, bar chart etc. All these widgets are added in ListView. Problem is that when i scroll inside table and reached to top or bottom then scroll in listview is not worked. I have to scroll outside of table to get scroll in ListView worked. Any solution for this? I have attached use case below. Screen_Recording_20210211-132212

    help wanted 
    opened by SachinTanpure 1
Owner
May Lau
Interested in frontend development, currently especially on flutter development.
May Lau
A Flutter widget for inputting content with a fixed length, visually treating each character as a separate segment.

code_input A Flutter widget for inputting content with a fixed length, visually treating each character as a separate segment. Pub Package GitHub Repo

Raouf Rahiche 69 Mar 25, 2022
A widget to provides horizontal or vertical multiple split view for Flutter.

Multi split view A widget to provides horizontal or vertical multiple split view for Flutter. Horizontal or vertical Configurable weight or size for e

Carlos Eduardo Leite de Andrade 63 Dec 28, 2022
Flutter widget form select a date in horizontal timeline with customizable styles.

Flutter widget form select a date in horizontal timeline with customizable styles. Getting Started You can use this package when you need to add a dat

Jose Manuel Márquez 158 Dec 2, 2022
A flutter horizontal date picker that always shift the selected date to center.

horizontal_center_date_picker A flutter widget provides a horizontal date picker and always aligns selected date in center of the widget. Usage This s

May Lau 5 Jul 2, 2022
Horizontal_calendar - Horizontal week view calendar pub for Flutter.

horizontal_calendar Easy to use, highly customizable horizontal calendar. Features Custom date range (First & Last Date) Single or up to x days select

SoluteLabs 74 Dec 19, 2022
A dart package to display a horizontal bar of customisable toggle tabs. Supports iOS and Android.

toggle_bar A dart package to display a horizontal bar of customisable toggle tabs. Supports iOS and Android. Installation Depend on it. dependencies:

Prem Adithya 9 Jul 13, 2022
Flutter multiplatform navigation sidebar / side navigationbar / drawer widget

SidebarX ?? Flutter multiplatform navigation sidebar / side navigationbar / drawer widget Show some ❤️ and star the repo to support the project! Mobil

Stanislav Ilin 138 Jan 5, 2023
A customizable listview with A-Z side scrollbar to fast jump to the item of the selected character

A customizable listview with A-Z side scrollbar to fast jump to the item of the selected character

Liew Jun Tung 81 Sep 21, 2022
A customizable listview with A-Z side scrollbar to fast jump to the item of the selected character.

A customizable listview with A-Z side scrollbar to fast jump to the item of the selected character. Quick scroll through list via dragging through alphabets.

Hussain Al Lawati 1 Apr 3, 2022
A repository to create and compare different methodologies of reusing local widget state logics.

A repository to create and compare different methodologies of reusing local widget state logics.

Tim Whiting 18 Dec 31, 2022
A simple Flutter widget to add in the widget tree when you want to show nothing, with minimal impact on performance.

nil A simple widget to add in the widget tree when you want to show nothing, with minimal impact on performance. Why? Sometimes, according to a condit

Romain Rastel 127 Dec 22, 2022
A flutter carousel widget, support infinite scroll, and custom child widget.

carousel_slider A carousel slider widget. Features Infinite scroll Custom child widgets Auto play Supported platforms Flutter Android Flutter iOS Flut

Bart T 1 Nov 25, 2021
A Flutter Widget to make interactive timeline widget.

Bubble Timeline Package A Flutter Widget to make interactive timeline widget. This widget can be used to make Event Timelines, or Timelines for certai

Vansh Goel 12 Sep 22, 2022
📸 Easy to use yet very customizable zoomable image widget for Flutter, Photo View provides a gesture sensitive zoomable widget.

?? Easy to use yet very customizable zoomable image widget for Flutter, Photo View provides a gesture sensitive zoomable widget. Photo View is largely used to show interacive images and other stuff such as SVG.

Blue Fire 1.7k Jan 7, 2023
A widget lib that the widget in this lib can react to flutter ScrollController's offset

Language: English | 中文简体 linked_scroll_widgets A lib full of widgets that can react to the scrollController's offset change,to custom your UI effect.

WenJingRui 8 Oct 16, 2022
Full customable rolling switch widget for flutter apps based on Pedro Massango's 'crazy-switch' widget

lite_rolling_switch Full customable rolling switch widget for flutter apps based on Pedro Massango's 'crazy-switch' widget https://github.com/pedromas

Eduardo Muñoz 48 Dec 1, 2022
Progress Dialog widget for flutter projects with ability to customize loading widget, background color and background blur.

DISCONTINUED Checkout ArsDialog ars_progress_dialog Customizable progress dialog for Flutter applications with smooth animation for background dim col

Arsam 8 Apr 15, 2022
A Flutter widget that will give a Glitch Animation Effect to it's child widget.

GlitchEffect A Flutter widget that will give a Glitch Animation Effect to it's child widget. Installation Add the latest version of package to your pu

Sameer Singh 6 Nov 25, 2022
Widget, that can make any static located widget hidable

Installing See the official installing guidline from hidable/install Usage & Overview To start using Hidable widget, we have to create a ScrollControl

Anon 18 Dec 16, 2022