Flutter Scrollbar in vertical and horizontal axis

Viewed 3867

I have two scrollbars in my flutter project for scrolling the data table. Here are the codes.

  Widget build(BuildContext context) {
    return Scaffold(
        body: Center(
            child: Container(
                width: MediaQuery.of(context).size.width * (1 / 2),
                height: MediaQuery.of(context).size.height * (1 / 2),
                child: Scrollbar(
                    isAlwaysShown: true,
                    controller: _controllerOne,
                    child: SingleChildScrollView(
                        scrollDirection: Axis.vertical,
                        controller: _controllerOne,
                        child: Scrollbar(
                          controller: _controllerTwo,
                          isAlwaysShown: true,
                          child: SingleChildScrollView(
                            scrollDirection: Axis.horizontal,
                            controller: _controllerTwo,
                            child: DataTable(
                             ...
                            ),
                          ),
                        ))))));
  }

These two scrollbars are working correctly. But I can not see both of them at the same time. I mean if I write the Scrollbar with scrollDirection in vertical first it's like;

enter image description here

Widget build(BuildContext context) {
    return Scaffold(
        body: Center(
            child: Container(
                width: MediaQuery.of(context).size.width * (1 / 2),
                height: MediaQuery.of(context).size.height * (1 / 2),
                child: Scrollbar(
                    isAlwaysShown: true,
                    controller: _controllerOne,
                    child: SingleChildScrollView(
                        **scrollDirection: Axis.vertical,**
                        controller: _controllerOne,
                        child: Scrollbar(
                          controller: _controllerTwo,
                          isAlwaysShown: true,
                          child: SingleChildScrollView(
                            **scrollDirection: Axis.horizontal,**
                            controller: _controllerTwo,
                            child: DataTable(
                             ...
                            ),
                          ),
                        ))))));
  }

if I write the Scrollbar with scrollDirection in horizontal first it's like;

enter image description here

Widget build(BuildContext context) {
    return Scaffold(
        body: Center(
            child: Container(
                width: MediaQuery.of(context).size.width * (1 / 2),
                height: MediaQuery.of(context).size.height * (1 / 2),
                child: Scrollbar(
                    isAlwaysShown: true,
                    controller: _controllerOne,
                    child: SingleChildScrollView(
                        **scrollDirection: Axis.horizontal,**
                        controller: _controllerOne,
                        child: Scrollbar(
                          controller: _controllerTwo,
                          isAlwaysShown: true,
                          child: SingleChildScrollView(
                            **scrollDirection: Axis.vertical,**
                            controller: _controllerTwo,
                            child: DataTable(
                             ...
                            ),
                          ),
                        ))))));
  }

When I scroll till the end I can see the other scrollbar for both directions. But when the table is shown I need to see them both at the same time.

Is there any solution for this?

3 Answers

Maybe this package will also help you easily customize your thumb and scrolling track both horizontally and vertically

cross scroll package

enter image description here

I suggest you to use InteractiveViewer for it's easier navigation when presenting large data on a table however to address your question you can actually do it without relying on any packages.

What you'll have to do is nest the vertical and horizontal SingleChildScrollView and wrap it with two ScrollBar then attach a ScrollController respectively and use the notificationPredicate property on the inner ScrollBar.

enter image description here

class MyWidget extends StatelessWidget {
  final List<int> shades = [100, 200, 300, 400, 500, 600, 700, 800, 900];
  final ScrollController _horizontal = ScrollController(),
      _vertical = ScrollController();

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: 500,
      width: 400,
      child: Scrollbar(
        controller: _vertical,
        thumbVisibility: true,
        trackVisibility: true,
        child: Scrollbar(
          controller: _horizontal,
          thumbVisibility: true,
          trackVisibility: true,
          notificationPredicate: (notif) => notif.depth == 1,
          child: SingleChildScrollView(
            controller: _vertical,
            child: SingleChildScrollView(
              controller: _horizontal,
              scrollDirection: Axis.horizontal,
              child: DataTable(
                columns: const <DataColumn>[
                  DataColumn(label: Text('Preview')),
                  DataColumn(label: Text('Color')),
                  DataColumn(label: Text('Shade')),
                ],
                rows: [
                  for (var color in Colors.primaries)
                    for (var shade in shades)
                      DataRow(
                        cells: [
                          DataCell(Container(
                              height: 20, width: 50, color: color[shade])),
                          DataCell(Text(color.toString())),
                          DataCell(Text('$shade')),
                        ],
                      ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}
Related