5

I've been building layout with both horizontal and vertical scrolling. Vertical scrollable Column is for main content and is populated by different views, including horizontal ListView which shows promo banners. I wanted to show scrollbar for vertical scrolling, but not for horizontal. I've wrapped the SingleChildScrollView which makes Column scrollable in ScrollBar, but the bar appeared on both vertical on horizontal scrolls. Is there any fine-tuning for these kinds of things?

Sample to demonstrate the issure

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Scrollables',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Scrollbar(
        child: new SingleChildScrollView(
            child: new Container(
          padding: EdgeInsets.only(top: 40.0),
          child: Column(children: <Widget>[
            HorizontalListView(),
            VerticalListView(),
          ]),
        )),
      ),
    );
  }
}

class HorizontalListView extends StatelessWidget {
  var items = new List<String>();

  _addNewItem(int index) {
    items.add("Item $index");
  }

  @override
  Widget build(BuildContext context) => Container(
      height: 120,
      child: ListView.builder(
          scrollDirection: Axis.horizontal,
          itemCount: 15,
          itemBuilder: (context, index) {
            return Card(child: ListItem(index));
          }));
}

class VerticalListView extends StatelessWidget {
  var items = new List<String>();

  _addNewItem(int index) {
    items.add("Item $index");
  }

  @override
  Widget build(BuildContext context) => Container(
      child: ListView.builder(
          scrollDirection: Axis.vertical,
          itemCount: 50,
          shrinkWrap: true,
          physics: const NeverScrollableScrollPhysics(),
          itemBuilder: (context, index) {
            return ListItem(index);
          }));
}

class ListItem extends StatelessWidget {
  int _index;
  ListItem(this._index);
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 280,
      child: Text("Item ${this._index}"),
    );
  }
}

Scrolling demonstration

Pay attention to the bottom on horizontal scrolling

Tumist
  • 119
  • 3
  • 11

2 Answers2

8
class NoScrollbar extends StatelessWidget {
  final Widget child;
  const NoScrollbar({Key key, this.child}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return NotificationListener<ScrollNotification>(
      onNotification: (_) => true,
      child: child,
    );
  }
}

Just wrap the NoScrollbar Widget around the Scrolling Widget, you don't want to have the Scrollbar appear. This solved it for me!

Niklas Raab
  • 1,576
  • 1
  • 16
  • 32
  • 2
    I don't understand how this works but it does work – MobileMon Dec 09 '20 at 12:53
  • @MobileMon flutter scrollbar is based on `ScrollNotification`s, and because returning `true` from the `NotificationListener` `onNotification` will prevent notication bubbling, it won't reach the `Scrollbar` widget and it thus it won't appear – nt4f04und Jan 23 '21 at 03:28
1

Niklas answer did not work for me in Flutter 2.5. I don't know if it's because my layout is different or what. But if you have a PageView (as a carousel for example) inside a ListView the way I found to remove PageView's scrollbar is the following.

Add to Scrollbar widget a notificationPredicate:

notificationPredicate: (ScrollNotification notification) {
  return notification.depth == 0 && notification.metrics.axis == Axis.vertical;
}

This will only show scrollbar for vertical interactions.

Flutter documentation about notificationPredicate.

guidoec
  • 11
  • 3