Kinda Code
Home/Flutter/Adding and Customizing a Scrollbar in Flutter

Adding and Customizing a Scrollbar in Flutter

Last updated: April 23, 2023

In Flutter, scrollable widgets (ListView, GridView, etc) have no scrollbar by default. A scrollbar lets a user know how long a view is. It indicates how far the user has scrolled from the top boundary and lets him or her quickly jump to a particular point.

In this article, we’ll have a look at the Scrollbar widget in Flutter and learn how to style and customize it through a couple of different examples (the last one implements a CupertinoScrollbar).

Overview

To add a scroll bar, just wrap your view with a Scrollbar widget. The only required parameter of a Scrollbar is a child widget. Others are optional.

ParameterTypeDescription
child (required)WidgetThe child widget of the Scrollbar (ListView, GridView, …)
thicknessdoubleThe thickness of the scrollbar
showTrackOnHoverboolDetermine whether the track will show on hover and remain, including during drag
controllerScrollControllerControls the Scrollbar dragging
hoverThicknessdoubleDetermine the thickness of the scrollbar when a hover state is active and showTrackOnHover is true
thumbVisibilityboolDetermine the scrollbar thumb will always remain visible or will fade out when it is not in use.
notificationPredicateScrollNotificationPredicateCheck whether a ScrollNotification should be handled by the Scrollbar
radiusRadiusSet the shape of the scrollbar thumb (rounded corners)

If the child widget of the Scrollbar has an infinite length (for example, when you use ListView.builder or GridView.builder without passing itemCount), the Scrollbar will not show up. However, there is no error message in this case.

Example 1: Basic Implementation

Preview:

The full code:

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Kindacode.com',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  HomePage({Key? key}) : super(key: key);

  // Dummy data
  final _myList = List.generate(50, (index) => 'Item $index');

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Kindacode.com'),
      ),
      body: Scrollbar(
        // I use a big thickness to make the thumb is easy to be seen
        // You should chose another number that makes more sense
        thickness: 10,
        thumbVisibility: true,
        radius: const Radius.circular(10), // give the thumb rounded corners
        child: ListView.builder(
          itemCount: _myList.length, // Don't forget this line
          itemBuilder: (context, index) => Card(
            key: ValueKey(_myList[index]),
            margin: const EdgeInsets.all(15),
            elevation: 5,
            color: Colors.accents[Random().nextInt(Colors.accents.length)],
            child: ListTile(
              title: Text(
                _myList[index],
                style: const TextStyle(fontSize: 24),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

Example 2: Using scrollbarTheme

In this example, we’ll style the Scrollbar by using the ScrollbarThemeData class. Color, minimum thumb length, scrollbar margin, and much more are all set as we want.

Note: Since the Scrollbar dynamically changes to an iOS-style scrollbar on the iOS platform, using scrollbarTheme only makes effects on Android as you can see in the video below.

Preview:

The full code:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Kindacode.com',
      theme: ThemeData(
          primarySwatch: Colors.green,
          scrollbarTheme: ScrollbarThemeData(
              thumbVisibility: MaterialStateProperty.all(true),
              thickness: MaterialStateProperty.all(10),
              thumbColor: MaterialStateProperty.all(Colors.blue),
              radius: const Radius.circular(10),
              minThumbLength: 100)),
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  HomePage({Key? key}) : super(key: key);

  // Generating dummy data for testing purpose
  final List dummyData = List.generate(100, (index) => '$index');
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Kindacode.com'),
      ),
      body: Scrollbar(
        child: GridView.builder(
          itemCount: dummyData.length,
          gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
              maxCrossAxisExtent: 200,
              childAspectRatio: 3 / 2,
              crossAxisSpacing: 20,
              mainAxisSpacing: 20),
          itemBuilder: (context, index) {
            return GridTile(
                child: Container(
              color: Colors.amberAccent,
              alignment: Alignment.center,
              child: Text(
                dummyData[index],
                style: const TextStyle(fontSize: 24),
              ),
            ));
          },
        ),
      ),
    );
  }
}

Example 3: Using CupertinoScrollbar

Using the CupertinoScrollbar widget is quite similar to using the Scrollbar widget. Don’t forget to import the cupertino library into your code:

import 'package:flutter/cupertino.dart';

Screenshot:

The full code:

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Kindacode.com',
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  HomePage({Key? key}) : super(key: key);

  // Generating dummy data for testing purpose
  final List dummyData = List.generate(100, (index) => '$index');

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Kindacode.com'),
      ),
      body: CupertinoScrollbar(
          thickness: 8,
          thumbVisibility: true,
          child: ListView.builder(
            itemCount: dummyData.length,
            itemBuilder: (context, index) => Card(
              color: Colors.blue[200],
              child: Padding(
                padding: const EdgeInsets.all(30),
                child: Center(
                  child: Text(
                    dummyData[index],
                    style: const TextStyle(fontSize: 30),
                  ),
                ),
              ),
            ),
          )),
    );
  }
}

Conclusion

We’ve explored a lot of things about the Scrollbar widget and walked over a few examples of using it in applications. If you’d like to learn more new and fascinating stuff in Flutter, take a look at the following articles:

You can also check out our Flutter topic page or Dart topic page for the latest tutorials and examples. Have a nice day and happy Fluttering.