Default drag scrolling devices
Summary
ScrollBehavior
s now allow or disallow drag scrolling from specified
PointerDeviceKind
s. ScrollBehavior.dragDevices
, by default,
allows scrolling widgets to be dragged by all PointerDeviceKind
s
except for PointerDeviceKind.mouse
.
Context
Prior to this change, all PointerDeviceKind
s could drag a Scrollable
widget.
This did not match developer expectations when interacting with Flutter
applications using mouse input devices. This also made it difficult to execute
other mouse gestures, like selecting text that was contained in a Scrollable
widget.
Now, the inherited ScrollBehavior
manages which devices can drag scrolling widgets
as specified by ScrollBehavior.dragDevices
. This set of PointerDeviceKind
s are
allowed to drag.
Description of change
This change fixed the unexpected ability to scroll by dragging with a mouse.
If you have relied on the previous behavior in your application, there are several ways to control and configure this feature.
-
Extend
ScrollBehavior
,MaterialScrollBehavior
, orCupertinoScrollBehavior
to modify the default behavior, overridingScrollBehavior.dragDevices
.- With your own
ScrollBehavior
, you can apply it app-wide by settingMaterialApp.scrollBehavior
orCupertinoApp.scrollBehavior
. - Or, if you wish to only apply it to specific widgets, add a
ScrollConfiguration
above the widget in question with your customScrollBehavior
.
- With your own
Your scrollable widgets then inherit and reflect this behavior.
-
Instead of creating your own
ScrollBehavior
, another option for changing the default behavior is to copy the existingScrollBehavior
, and set differentdragDevices
.- Create a
ScrollConfiguration
in your widget tree, and provide a modified copy of the existingScrollBehavior
in the current context usingcopyWith
.
- Create a
To accommodate the new configuration of drag devices in ScrollBehavior
,
GestureDetector.kind
has been deprecated along with all subclassed instances of the parameter.
A flutter fix is available to migrate existing code for all gesture detectors from kind
to supportedDevices
. The previous parameter kind
only allowed one PointerDeviceKind
to
be used to filter gestures. The introduction of supportedDevices
makes it possible for more
than one valid PointerDeviceKind
.
Migration guide
ScrollBehavior
for your application
Setting a custom Code before migration:
MaterialApp(
// ...
);
Code after migration:
class MyCustomScrollBehavior extends MaterialScrollBehavior {
// Override behavior methods and getters like dragDevices
@override
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
// etc.
};
}
// Set ScrollBehavior for an entire application.
MaterialApp(
scrollBehavior: MyCustomScrollBehavior(),
// ...
);
ScrollBehavior
for a specific widget
Setting a custom Code before migration:
final ScrollController controller = ScrollController();
ListView.builder(
controller: controller,
itemBuilder: (BuildContext context, int index) {
return Text('Item $index');
}
);
Code after migration:
class MyCustomScrollBehavior extends MaterialScrollBehavior {
// Override behavior methods and getters like dragDevices
@override
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
// etc.
};
}
// ScrollBehavior can be set for a specific widget.
final ScrollController controller = ScrollController();
ScrollConfiguration(
behavior: MyCustomScrollBehavior(),
child: ListView.builder(
controller: controller,
itemBuilder: (BuildContext context, int index) {
return Text('Item $index');
}
),
);
ScrollBehavior
Copy and modify existing Code before migration:
final ScrollController controller = ScrollController();
ListView.builder(
controller: controller,
itemBuilder: (BuildContext context, int index) {
return Text('Item $index');
}
);
Code after migration:
// ScrollBehavior can be copied and adjusted.
final ScrollController controller = ScrollController();
ScrollConfiguration(
behavior: ScrollConfiguration.of(context).copyWith(dragDevices: {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
}),
child: ListView.builder(
controller: controller,
itemBuilder: (BuildContext context, int index) {
return Text('Item $index');
}
),
);
GestureDetector
s from kind
to supportedDevices
Migrate Code before migration:
VerticalDragGestureRecognizer(
kind: PointerDeviceKind.touch,
);
Code after migration:
VerticalDragGestureRecognizer(
supportedDevices: <PointerDeviceKind>{ PointerDeviceKind.touch },
);
Timeline
Landed in version: 2.3.0-12.0.pre
In stable release: 2.5
References
API documentation:
ScrollConfiguration
ScrollBehavior
MaterialScrollBehavior
CupertinoScrollBehavior
PointerDeviceKind
GestureDetector
Relevant issues:
Relevant PRs: