Skip to content

Conversation

@HansMuller
Copy link
Contributor

@HansMuller HansMuller commented Apr 11, 2024

The scroll notification events reported for a press-drag-release gesture within a scrollable on a touch screen device begin with a ScrollStartNotification, followed by a series of ScrollUpdateNotifications, and conclude with a ScrollEndNotification. This protocol can be used to defer work until an interactive scroll gesture ends. For example, you might defer updating a scrollable's contents via network requests until the scroll has ended, or you might want to automatically auto-scroll at that time.

In the example that follows the CustomScrollView automatically scrolls so that the last partially visible fixed-height item is completely visible when the scroll gesture ends. Many iOS applications do this kind of thing. It only makes sense to auto-scroll when the user isn't actively dragging the scrollable around.

It's easy enough to do this by reacting to a ScrollEndNotifcation by auto-scrolling to align the last fixed-height list item (source code).

Screen.Recording.2024-02-05.at.4.30.46.PM.mov

Dragging the scrollbar thumb in a desktop application is a similar user gesture. Currently it's not possible to defer work or auto-scroll (or whatever) while the scrollable is actively being dragged via the scrollbar thumb because each scrollbar thumb motion is mapped to a scroll start - scroll update - scroll end series of notifications. On a desktop platform, the same code behaves quite differently when the scrollbar thumb is dragged.

Screen.Recording.2024-02-05.at.9.45.41.AM.mov

The stream of scroll-end events triggers auto-scrolling every time the thumb moves. From the user's perspective this feels like a losing struggle.

One can also detect the beginning and end of a touch-drag by listening to the value of a ScrollPosition's isScrollingNotifier. This approach suffers from a similar problem: during a scrollbar thumb-drag, the isScrollingNotifier value isn't updated at all.

This PR refactors the RawScrollbar implementation to effectively use a ScrollDragController to manage scrolls caused by dragging the scrollbar's thumb. Doing so means that dragging the thumb will produce the same notifications as dragging the scrollable on a touch device.

Now desktop applications can choose to respond to scrollbar thumb drags in the same that they respond to drag scrolling on a touch screen. With the changes included here, the desktop or web version of the app works as expected, whether you're listing to scroll notifications or the scroll position's isScrollingNotifier.

Screen.Recording.2024-02-02.at.4.04.51.PM.mov

This PR also makes the second ScrollPosition API doc example work as expected when used with the DartPad that's part of API doc page.

Desktop applications also see scroll start-update-end notifications due to the mouse wheel. There is no touch screen analog for the mouse wheel, so an application that wanted to enable this kind of auto-scrolling alignment would have to include a heuristic that dealt with the sequence of small scrolls triggered by the mouse wheel. Here's an example of that: source code. This version of the app does not auto-align in response to small changes, wether they're triggered by dragging the scrollbar thumb of the mouse wheel.

Related sliver utility PRs: #143538, #143196, #143325.

Part of #127334.

@github-actions github-actions bot added framework flutter/packages/flutter repository. See also f: labels. f: scrolling Viewports, list views, slivers, etc. d: api docs Issues with https://api.flutter.dev/ d: examples Sample code and demos labels Apr 11, 2024
@HansMuller HansMuller changed the title Scrollbar thumb drag gestures now produce one drag start scroll notification, and one drag end. Scrollbar thumb drag gestures now produce one start and one end scroll notification Apr 12, 2024
@Piinks Piinks self-requested a review April 12, 2024 19:58
@HansMuller HansMuller force-pushed the refactor_scrollbar branch 2 times, most recently from 5f87208 to 1091d36 Compare April 23, 2024 20:26
Copy link
Contributor

@Piinks Piinks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall I think this looks awesome, just a couple of questions

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this and the other sample, why are these post frame callbacks?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because when the notification arrives the ScrollPosition is still in its DragScrollActivity. So calls to animateTo are ignored per https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/widgets/scroll_position.dart#L995

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, this makes me wonder if folks that wanted to do this would be better off listening to the isScrollingNotifier on the position? I think when it changes to false it is safe to alter the scroll position at that point.
Doing so this way feels kind of advanced for users, and should also account for whether or not the context is still mounted in that callback.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The examples/api/lib/widgets/scroll_position/is_scrolling_listener.0.dart (included in this PR) does exactly that. This example is for ScrollEndNotification whose API doc does mention the isScrolling version of the example:

///  ...  This sort of thing can also
/// be done by listening to the [ScrollController]'s
/// [ScrollPosition.isScrollingNotifier]. An alternative example is provided
/// with [ScrollPosition.isScrollingNotifier].

Copy link
Contributor

@Piinks Piinks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, make it so. Nitty nit though on the sample code, WDYT?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, this makes me wonder if folks that wanted to do this would be better off listening to the isScrollingNotifier on the position? I think when it changes to false it is safe to alter the scroll position at that point.
Doing so this way feels kind of advanced for users, and should also account for whether or not the context is still mounted in that callback.

@HansMuller
Copy link
Contributor Author

Hmm, this makes me wonder if folks that wanted to do this would be better off listening to the isScrollingNotifier on the position?

See #146654 (comment)

@HansMuller HansMuller force-pushed the refactor_scrollbar branch from 72de709 to f13354c Compare June 3, 2024 21:21
@HansMuller HansMuller added the autosubmit Merge PR when tree becomes green via auto submit App label Jun 4, 2024
@auto-submit auto-submit bot merged commit 92f8455 into flutter:master Jun 4, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 4, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 5, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 5, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 5, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 5, 2024
auto-submit bot pushed a commit to flutter/packages that referenced this pull request Jun 5, 2024
flutter/flutter@c246ecd...27e0656

2024-06-05 98614782+auto-submit[bot]@users.noreply.github.com Reverts "TreeSliver & associated classes (#147171)" (flutter/flutter#149754)
2024-06-05 [email protected] Feature: Add AnimatedList with separators (flutter/flutter#144899)
2024-06-05 [email protected] make output of flutter run web tests verbose (flutter/flutter#149694)
2024-06-05 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Request focus if `SemanticsAction.focus` is sent to a focusable widget (#142942)" (flutter/flutter#149741)
2024-06-05 [email protected] Roll Flutter Engine from e88469090fed to 11a32d43e3f6 (2 revisions) (flutter/flutter#149699)
2024-06-05 [email protected] Request focus if `SemanticsAction.focus` is sent to a focusable widget (flutter/flutter#142942)
2024-06-04 [email protected] Roll Flutter Engine from 3dd40156afb6 to e88469090fed (2 revisions) (flutter/flutter#149695)
2024-06-04 [email protected] TreeSliver & associated classes (flutter/flutter#147171)
2024-06-04 [email protected] Roll Flutter Engine from fe00f023666c to 3dd40156afb6 (3 revisions) (flutter/flutter#149692)
2024-06-04 49699333+dependabot[bot]@users.noreply.github.com Bump github/codeql-action from 3.25.7 to 3.25.8 (flutter/flutter#149691)
2024-06-04 [email protected] Prepares semantics_update_test for upcoming heading level changes (flutter/flutter#149671)
2024-06-04 [email protected] Identify and re-throw our dependency checking errors in `flutter.groovy` (flutter/flutter#149609)
2024-06-04 [email protected] Scrollbar thumb drag gestures now produce one start and one end scroll notification (flutter/flutter#146654)
2024-06-04 [email protected] Disable sandboxing for macOS apps and tests in CI (flutter/flutter#149618)
2024-06-04 [email protected] Roll Flutter Engine from e211c43f3dc1 to fe00f023666c (3 revisions) (flutter/flutter#149680)
2024-06-04 [email protected] Allow `find.byTooltip` to use a RegEx (flutter/flutter#149348)
2024-06-04 [email protected] Roll Flutter Engine from a6aa5d826649 to e211c43f3dc1 (8 revisions) (flutter/flutter#149658)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC [email protected],[email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
@HansMuller HansMuller deleted the refactor_scrollbar branch June 6, 2024 00:00
@QuncCccccc
Copy link
Contributor

This PR seems cause a regression issue when there is a nested ListViews:)

Here is the sample code to test. In the demo, I'm trying to scroll to the right, but it doesn't work all the time and vertical thumb bar looks highlighted even when I scroll horizontally.

Screen.Recording.2024-06-13.at.4.00.09.PM.mov
Details
import 'package:flutter/material.dart';

void main() => runApp(const CarouselExampleApp());

class CarouselExampleApp extends StatelessWidget {
  const CarouselExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Sample'),
        ),
        body: const CarouselExample(),
      ),
    );
  }
}

class CarouselExample extends StatefulWidget {
  const CarouselExample({super.key});

  @override
  State<CarouselExample> createState() => _CarouselExampleState();
}

class _CarouselExampleState extends State<CarouselExample> {
  @override
  Widget build(BuildContext context) {
    return ListView(
      children: <Widget>[
        Container(
          width: 200,
          height: 200,
          color: Colors.amber[50],
        ),
        Center(
          child: ConstrainedBox(
            constraints: const BoxConstraints(maxHeight: 200),
            child: ListView(
              scrollDirection: Axis.horizontal,
              children: List.generate(20, (int index) {
                return ConstrainedBox(constraints: BoxConstraints.tightFor(width: 200), child: Card.outlined(child: SizedBox(width: 200, height: 200, child: Center(child: Text('Item $index')),),),);
              }),
            )
          ),
        ),
        Container(
          width: 200,
          height: 200,
          color: Colors.amber[100],
        ),
        Container(
          width: 200,
          height: 200,
          color: Colors.amber[200],
        ),
      ],
    );
  }
}

CC: @Piinks

@Piinks
Copy link
Contributor

Piinks commented Jun 13, 2024

@QuncCccccc can you put that in a new issue and cc @HansMuller?
I know there are some other regressions around this as well, should we consider reverting it until all of the issues are resolved?

auto-submit bot pushed a commit that referenced this pull request Jun 27, 2024
…pad (#150275)

Corrects some problems related to trackpad scrolls introduced by #146654.

Fixes #149999
Fixes #150342
Fixes #150236
victorsanni pushed a commit to victorsanni/flutter that referenced this pull request Jul 8, 2024
…pad (flutter#150275)

Corrects some problems related to trackpad scrolls introduced by flutter#146654.

Fixes flutter#149999
Fixes flutter#150342
Fixes flutter#150236
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autosubmit Merge PR when tree becomes green via auto submit App d: api docs Issues with https://api.flutter.dev/ d: examples Sample code and demos f: scrolling Viewports, list views, slivers, etc. framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants