ScrollbarModifier class

A Material Design scrollbar.

To add a scrollbar to a ScrollView, wrap the scroll view widget in a Scrollbar widget.

A scrollbar thumb indicates which portion of a ScrollView is actually visible.

By default, the thumb will fade in and out as the child scroll view scrolls. When thumbVisibility is true, the scrollbar thumb will remain visible without the fade animation. This requires that the ScrollController associated with the Scrollable widget is provided to controller, or that the PrimaryScrollController is being used by that Scrollable widget.

If the scrollbar is wrapped around multiple ScrollViews, it only responds to the nearest ScrollView and shows the corresponding scrollbar thumb by default. The notificationPredicate allows the ability to customize which ScrollNotifications the Scrollbar should listen to.

If the child ScrollView is infinitely long, the RawScrollbar will not be painted. In this case, the scrollbar cannot accurately represent the relative location of the visible area, or calculate the accurate delta to apply when dragging on the thumb or tapping on the track.

Interaction

Scrollbars are interactive and can use the PrimaryScrollController if a controller is not set. Interactive Scrollbar thumbs can be dragged along the main axis of the ScrollView to change the ScrollPosition. Tapping along the track exclusive of the thumb will trigger a ScrollIncrementType.page based on the relative position to the thumb.

When using the PrimaryScrollController, it must not be attached to more than one ScrollPosition. ScrollViews that have not been provided a ScrollController and have a ScrollView.scrollDirection of Axis.vertical will automatically attach their ScrollPosition to the PrimaryScrollController. Provide a unique ScrollController to each Scrollable in this case to prevent having multiple ScrollPositions attached to the PrimaryScrollController.

{@tool dartpad} This sample shows an app with two scrollables in the same route. Since by default, there is one PrimaryScrollController per route, and they both have a scroll direction of Axis.vertical, they would both try to attach to that controller on mobile platforms. The Scrollbar cannot support multiple positions attached to the same controller, so one ListView, and its Scrollbar have been provided a unique ScrollController. Desktop platforms do not automatically attach to the PrimaryScrollController, requiring ScrollView.primary to be true instead in order to use the PrimaryScrollController.

Alternatively, a new PrimaryScrollController could be created above one of the ListViews.

** See code in examples/api/lib/widgets/scrollbar/raw_scrollbar.0.dart ** {@end-tool}

Automatic Scrollbars on Desktop Platforms

Scrollbars are added to most Scrollable widgets by default on TargetPlatformVariant.desktop platforms. This is done through ScrollBehavior.buildScrollbar as part of an app's ScrollConfiguration. Scrollables that do not use the PrimaryScrollController or have a ScrollController provided to them will receive a unique ScrollController for use with the Scrollbar. In this case, only one Scrollable can be using the PrimaryScrollController, unless interactive is false. To prevent Axis.vertical Scrollables from using the PrimaryScrollController, set ScrollView.primary to false. Scrollable widgets that do not have automatically applied Scrollbars include

Default Scrollbars can be disabled for the whole app by setting a ScrollBehavior with scrollbars set to false.

{@tool snippet}

MaterialApp(
  scrollBehavior: const MaterialScrollBehavior()
    .copyWith(scrollbars: false),
  home: Scaffold(
    appBar: AppBar(title: const Text('Home')),
  ),
)

{@end-tool}

{@tool dartpad} This sample shows how to disable the default Scrollbar for a Scrollable widget to avoid duplicate Scrollbars when running on desktop platforms.

** See code in examples/api/lib/widgets/scrollbar/raw_scrollbar.desktop.0.dart ** {@end-tool}

Dynamically changes to a CupertinoScrollbar, an iOS style scrollbar, by default on the iOS platform.

The color of the Scrollbar thumb will change when MaterialState.dragged, or MaterialState.hovered on desktop and web platforms. These stateful color choices can be changed using ScrollbarThemeData.thumbColor.

{@tool dartpad} This sample shows a Scrollbar that executes a fade animation as scrolling occurs. The Scrollbar will fade into view as the user scrolls, and fade out when scrolling stops.

** See code in examples/api/lib/material/scrollbar/scrollbar.0.dart ** {@end-tool}

{@tool dartpad} When thumbVisibility is true, the scrollbar thumb will remain visible without the fade animation. This requires that a ScrollController is provided to controller, or that the PrimaryScrollController is available.

When a ScrollView.scrollDirection is Axis.horizontal, it is recommended that the Scrollbar is always visible, since scrolling in the horizontal axis is less discoverable.

** See code in examples/api/lib/material/scrollbar/scrollbar.1.dart ** {@end-tool}

A scrollbar track can be added using trackVisibility. This can also be drawn when triggered by a hover event, or based on any MaterialState by using ScrollbarThemeData.trackVisibility.

The thickness of the track and scrollbar thumb can be changed dynamically in response to MaterialStates using ScrollbarThemeData.thickness.

See also:

  • RawScrollbar, a basic scrollbar that fades in and out, extended by this class to add more animations and behaviors.
  • ScrollbarTheme, which configures the Scrollbar's appearance.
  • CupertinoScrollbar, an iOS style scrollbar.
  • ListView, which displays a linear, scrollable list of children.
  • GridView, which displays a 2 dimensional, scrollable array of children.
Inheritance
Available extensions

Constructors

ScrollbarModifier({Key? key, Widget? child, Key? modifierKey, ScrollController? controller, bool? thumbVisibility, bool? trackVisibility, double? thickness, Radius? radius, ScrollNotificationPredicate? notificationPredicate, bool? interactive, ScrollbarOrientation? scrollbarOrientation, @Deprecated('Use thumbVisibility instead. ' 'This feature was deprecated after v2.9.0-1.0.pre.') bool? isAlwaysShown, @Deprecated('Use ScrollbarThemeData.trackVisibility to resolve based on the current state instead. ' 'This feature was deprecated after v2.9.0-1.0.pre.') bool? showTrackOnHover, @Deprecated('Use ScrollbarThemeData.thickness to resolve based on the current state instead. ' 'This feature was deprecated after v2.9.0-1.0.pre.') double? hoverThickness})
Creates a Material Design scrollbar that by default will connect to the closest Scrollable descendant of child.
const

Properties

controller ScrollController?
The ScrollController used to implement Scrollbar dragging.
final
hashCode int
The hash code for this object.
no setterinherited
hoverThickness double?
The thickness of the scrollbar when a hover state is active and showTrackOnHover is true.
final
interactive bool?
Whether the Scrollbar should be interactive and respond to dragging on the thumb, or tapping in the track area.
final
isAlwaysShown bool?
Indicates that the scrollbar thumb should be visible, even when a scroll is not underway.
final
key Key?
Controls how one widget replaces another widget in the tree.
finalinherited
modifierKey Key?
The actual key of the widget, which Modifier wrapped
finalinherited
notificationPredicate ScrollNotificationPredicate?
A check that specifies whether a ScrollNotification should be handled by this widget.
final
radius Radius?
The Radius of the scrollbar thumb's rounded rectangle corners.
final
runtimeType Type
A representation of the runtime type of the object.
no setterinherited
scrollbarOrientation ScrollbarOrientation?
Dictates the orientation of the scrollbar.
final
showTrackOnHover bool?
Controls if the track will show on hover and remain, including during drag.
final
thickness double?
The thickness of the scrollbar in the cross axis of the scrollable.
final
thumbVisibility bool?
Indicates that the scrollbar thumb should be visible, even when a scroll is not underway.
final
trackVisibility bool?
Indicates that the scrollbar track should be visible.
final

Methods

build(BuildContext context) Widget
Describes the part of the user interface represented by this widget.
inherited
buildWithChild(BuildContext context, Widget? child) Widget
A build method that receives an extra child parameter.
override
createElement() SingleChildStatelessElement
Create a SingleChildStatelessElement
inherited
debugDescribeChildren() List<DiagnosticsNode>
Returns a list of DiagnosticsNode objects describing this node's children.
inherited
debugFillProperties(DiagnosticPropertiesBuilder properties) → void
Add additional properties associated with the node.
inherited
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
toDiagnosticsNode({String? name, DiagnosticsTreeStyle? style}) DiagnosticsNode
Returns a debug representation of the object that is used by debugging tools and by DiagnosticsNode.toStringDeep.
inherited
toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) String
A string representation of this object.
inherited
toStringDeep({String prefixLineOne = '', String? prefixOtherLines, DiagnosticLevel minLevel = DiagnosticLevel.debug}) String
Returns a string representation of this node and its descendants.
inherited
toStringShallow({String joiner = ', ', DiagnosticLevel minLevel = DiagnosticLevel.debug}) String
Returns a one-line detailed description of the object.
inherited
toStringShort() String
A short, textual description of this widget.
inherited

Operators

operator ==(Object other) bool
The equality operator.
inherited