Skip to content

Make EdgeDraggingAutoScroller respect ScrollPhysics#186541

Merged
mbcorona merged 7 commits into
flutter:masterfrom
mbcorona:fix-140654-edge-autoscroller-physics
May 19, 2026
Merged

Make EdgeDraggingAutoScroller respect ScrollPhysics#186541
mbcorona merged 7 commits into
flutter:masterfrom
mbcorona:fix-140654-edge-autoscroller-physics

Conversation

@mbcorona

Copy link
Copy Markdown
Member

Fixes #140654

Problem

When a Scrollable with NeverScrollableScrollPhysics lives under a SelectionArea, drag-selecting past the edge of the viewport still auto-scrolls it, and can additionally trip the "Drag target size is larger than scrollable size, which may cause bouncing" assertion in scrollable_helpers.dart. The original report uses a PageView(physics: NeverScrollableScrollPhysics()) containing a DataTable; reproduces on web, macOS, and Android, back to 3.16.

Root cause

EdgeDraggingAutoScroller._scroll() advances the scroll position by calling ScrollPosition.animateTo(...) directly. That bypasses ScrollPhysics.applyUserOffset / applyBoundaryConditions, so a Scrollable whose physics returns false from shouldAcceptUserOffset was still being driven during a drag-select. The two other user-driven scroll entry points already had this guard — ScrollAction.invoke in scrollable_helpers.dart and Scrollable._receivedPointerSignal in scrollable.dart — the auto-scroller was the missing one. The assertion lives inside _scroll(), so it fires only because _scroll() runs when it shouldn't; gating physics resolves both symptoms in one place.

(Root cause originally diagnosed by @Renzo-Olivares on the issue thread)

Change

EdgeDraggingAutoScroller.startAutoScrollIfNecessary now consults scrollable.resolvedPhysics.shouldAcceptUserOffset(scrollable.position). If physics refuses user offset, it stopAutoScroll()s and returns early — mirroring the pattern at the existing guard sites. No new public API.

The auto-scroller is shared infrastructure: SliverReorderableList uses the same startAutoScrollIfNecessary for drag-reorder auto-scroll. Under default physics the new guard is a pass-through, so reorder behavior is unchanged; the existing SliverReorderableList auto scrolls speed is configurable test serves as the regression guard and still passes.

Test

Added a testWidgets in scrollable_selection_test.dart that mouse-drag-selects past the bottom of a ListView wrapped in a SelectionArea with NeverScrollableScrollPhysics, then asserts the scroll offset stays at 0.0 and no exception is thrown. The new test fails on master with Expected: <0.0> Actual: <20.0> and passes with this change.

Manual verification

Tested with the original repro (a SelectionArea > PageView(NeverScrollableScrollPhysics) with a DataTable first page and a Text second page). Before: drag-selecting near the right edge of the DataTable slid the PageView to page 2 and threw the assertion. After: PageView stays on page 1 and selection continues normally. Video attached.

Screen.Recording.2026-05-14.at.11.07.19.a.m.mov

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

If this change needs to override an active code freeze, provide a comment explaining why. The code freeze workflow can be overridden by code reviewers. See pinned issues for any active code freezes with guidance.

Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the gemini-code-assist bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

@flutter-dashboard flutter-dashboard Bot added the CICD Run CI/CD label May 14, 2026
@github-actions github-actions Bot added framework flutter/packages/flutter repository. See also f: labels. f: scrolling Viewports, list views, slivers, etc. labels May 14, 2026
@mbcorona mbcorona requested a review from Renzo-Olivares May 14, 2026 18:48

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request modifies the EdgeDraggingAutoScroller to respect scroll physics that disallow user offsets, such as NeverScrollableScrollPhysics, by preventing or stopping auto-scroll. A regression test was added to ensure this behavior and prevent future regressions. Feedback was provided to simplify the implementation by removing a redundant null check on the non-nullable resolvedPhysics property, aligning with the repository's readability guidelines.

Comment thread packages/flutter/lib/src/widgets/scrollable_helpers.dart

@navaronbracke navaronbracke left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just some remarks on the test

Comment thread packages/flutter/test/widgets/scrollable_selection_test.dart Outdated
await tester.pumpWidget(
MaterialApp(
home: SelectionArea(
selectionControls: materialTextSelectionControls,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we use testTextSelectionHandleControls, per the same remark about using Material here ?

);
await tester.pumpAndSettle();

final RenderParagraph paragraph0 = tester.renderObject<RenderParagraph>(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there a reason this requires finding the paragraph, as opposed to just using a text finder, and using for example the center of the text for the gesture start position?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

That makes sense to me. We only use RenderParagraph if we need to precisely select and/or verify the TextSelection or other RenderParagraph members.

Co-authored-by: Navaron Bracke <brackenavaron@gmail.com>
@github-actions github-actions Bot removed the CICD Run CI/CD label May 14, 2026
addTearDown(controller.dispose);
await tester.pumpWidget(
TestWidgetsApp(
home: SelectionArea(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should use SelectableRegion here instead of SelectionArea to avoid using Material in the widgets library tests.


// Drag past the bottom of the scrollable; this would normally trigger
// edge auto-scroll.
await gesture.moveTo(tester.getBottomRight(find.byType(ListView)) + const Offset(0, 40));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: per the style guide use double literals for double constants https://github.com/flutter/flutter/blob/master/docs/contributing/Style-guide-for-Flutter-repo.md#use-double-literals-for-double-constants

Offset(0, 40) -> Offset(0.0, 40.0).

});

testWidgets(
'drag-select edge auto-scroll respects NeverScrollableScrollPhysics',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think this can just be automatic edge scrolling respects NeverScrollableScrollPhysics.

Comment on lines +1452 to +1455
// A Scrollable whose physics refuses user offset (e.g.
// NeverScrollableScrollPhysics) must not be advanced by the selection
// edge auto-scroller, and the auto-scroller must not trip its drag-target
// size assertion in the process.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Consider the wording below to avoid specific implementation details that may not be true in the future.

// When a scrollable view with non-scrollable physics (e.g.,
// NeverScrollableScrollPhysics) is wrapped in a SelectableRegion, dragging
// a selection past the viewport boundary must not advance the scroll offset
// or throw exceptions.

@Renzo-Olivares

Copy link
Copy Markdown
Contributor

Hi @mbcorona, thank you for working on this! The code change LGTM just some small documentation comments.

await tester.pump();
await tester.pump(const Duration(seconds: 1));

// The scroll position must not have advanced, and no exception (e.g. the

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think leaving as "no exception must have been thrown" is good enough. The specific assertion text may change so this specific comment may not be true later on.


await gesture.up();
await tester.pumpAndSettle();
expect(tester.takeException(), isNull);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

consider checking controller.offset again after the pumpAndSettle.

@flutter-dashboard flutter-dashboard Bot added the CICD Run CI/CD label May 15, 2026
@mbcorona

Copy link
Copy Markdown
Member Author

@Renzo-Olivares @navaronbracke — pushed addressing all your comments. Ready for re-review when you have a minute.

navaronbracke
navaronbracke previously approved these changes May 15, 2026
@navaronbracke

Copy link
Copy Markdown
Contributor

Looks like Linux analyze is not happy with some of the formatting

/// If the scrollable is already scrolling, calling this method updates the
/// previous dragTarget to the new value and continues scrolling if necessary.
///
/// If the [scrollable]'s [ScrollableState.resolvedPhysics] refuses user

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: user offset -> user-driven scrolling.

Renzo-Olivares
Renzo-Olivares previously approved these changes May 15, 2026

@Renzo-Olivares Renzo-Olivares left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM modulo linux analyzer issues. Thank you for the fix @mbcorona and the quick changes!

@mbcorona mbcorona enabled auto-merge May 16, 2026 02:34
@mbcorona mbcorona dismissed stale reviews from Renzo-Olivares and navaronbracke via b79145a May 16, 2026 02:53
@github-actions github-actions Bot removed the CICD Run CI/CD label May 16, 2026
@flutter-dashboard flutter-dashboard Bot added the CICD Run CI/CD label May 18, 2026
@mbcorona mbcorona requested a review from Renzo-Olivares May 18, 2026 19:56
Renzo-Olivares
Renzo-Olivares previously approved these changes May 19, 2026

@Renzo-Olivares Renzo-Olivares left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM, thank you for the fix @mbcorona!

@flutter-dashboard flutter-dashboard Bot added the CICD Run CI/CD label May 19, 2026

@Renzo-Olivares Renzo-Olivares left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

RE-LGTM

@mbcorona mbcorona added this pull request to the merge queue May 19, 2026
Merged via the queue into flutter:master with commit f46f3fe May 19, 2026
84 of 85 checks passed
@mbcorona mbcorona deleted the fix-140654-edge-autoscroller-physics branch May 19, 2026 21:25
auto-submit Bot pushed a commit to flutter/packages that referenced this pull request May 20, 2026
flutter/flutter@259aeae...e03b91f

2026-05-20 engine-flutter-autoroll@skia.org Roll Packages from ade10ca to 1dfbada (6 revisions) (flutter/flutter#186811)
2026-05-20 brunocorona.alcantar@gmail.com Fix AnimatedList.separated assert when removing last item mid-removal… (flutter/flutter#186389)
2026-05-20 engine-flutter-autoroll@skia.org Roll Skia from d45969a5752e to 5f4f454b9662 (2 revisions) (flutter/flutter#186809)
2026-05-20 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from -F9Ci3Opxt06MixDl... to iKCvaD58jKStYGla0... (flutter/flutter#186796)
2026-05-20 engine-flutter-autoroll@skia.org Roll Skia from 19ad9707e5c6 to d45969a5752e (2 revisions) (flutter/flutter#186792)
2026-05-20 engine-flutter-autoroll@skia.org Roll Skia from 3471ebf5af0c to 19ad9707e5c6 (9 revisions) (flutter/flutter#186772)
2026-05-20 mdebbar@google.com [web] Refactor webparagraph painters to separate CK properly (flutter/flutter#186684)
2026-05-19 31859944+LongCatIsLooong@users.noreply.github.com Enable Swift testing in the iOS embedder (flutter/flutter#185712)
2026-05-19 mdebbar@google.com [web] Rename WebParagraph goldens (flutter/flutter#186680)
2026-05-19 engine-flutter-autoroll@skia.org Roll Skia from f1b406860c5e to 3471ebf5af0c (5 revisions) (flutter/flutter#186745)
2026-05-19 154381524+flutteractionsbot@users.noreply.github.com Revert "Ship gen_snapshot for linux-arm64 hosts targeting Android" (flutter/flutter#186693)
2026-05-19 bkonyi@google.com [ Tool ] Remove legacy analytics code (flutter/flutter#184994)
2026-05-19 chingjun@google.com Update Vulkan enum values (flutter/flutter#186694)
2026-05-19 1961493+harryterkelsen@users.noreply.github.com fix(web): Fixes CSS override detection when the browser has a default font size (flutter/flutter#186474)
2026-05-19 30870216+gaaclarke@users.noreply.github.com adds linux impeller hello world integration test (flutter/flutter#186715)
2026-05-19 jason-simmons@users.noreply.github.com Update the list of binaries in the code signing verification test to include new Dart snapshots (flutter/flutter#186754)
2026-05-19 brunocorona.alcantar@gmail.com Make EdgeDraggingAutoScroller respect ScrollPhysics (flutter/flutter#186541)
2026-05-19 bkonyi@google.com [ Widget Preview ] Fix inspector split resize focus loss over WebViews (flutter/flutter#186432)
2026-05-19 engine-flutter-autoroll@skia.org Roll Packages from b9bdd37 to ade10ca (1 revision) (flutter/flutter#186746)
2026-05-19 jason-simmons@users.noreply.github.com Manual Dart roll from 8e30b88e4d5a to 66873d2da857 (flutter/flutter#186690)
2026-05-19 bkonyi@google.com [ Widget Preview ] Improve zoom behavior and add zoom slider (flutter/flutter#186422)

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 stuartmorgan@google.com 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
matthewhendrix pushed a commit to matthewhendrix/flutter that referenced this pull request May 23, 2026
Fixes flutter#140654

## Problem

When a `Scrollable` with `NeverScrollableScrollPhysics` lives under a
`SelectionArea`, drag-selecting past the edge of the viewport still
auto-scrolls it, and can additionally trip the *"Drag target size is
larger than scrollable size, which may cause bouncing"* assertion in
`scrollable_helpers.dart`. The original report uses a `PageView(physics:
NeverScrollableScrollPhysics())` containing a `DataTable`; reproduces on
web, macOS, and Android, back to 3.16.

## Root cause

`EdgeDraggingAutoScroller._scroll()` advances the scroll position by
calling `ScrollPosition.animateTo(...)` directly. That bypasses
`ScrollPhysics.applyUserOffset` / `applyBoundaryConditions`, so a
`Scrollable` whose physics returns `false` from `shouldAcceptUserOffset`
was still being driven during a drag-select. The two other user-driven
scroll entry points already had this guard — `ScrollAction.invoke` in
`scrollable_helpers.dart` and `Scrollable._receivedPointerSignal` in
`scrollable.dart` — the auto-scroller was the missing one. The assertion
lives inside `_scroll()`, so it fires only because `_scroll()` runs when
it shouldn't; gating physics resolves both symptoms in one place.

(Root cause originally diagnosed by @Renzo-Olivares on the issue thread)

## Change

`EdgeDraggingAutoScroller.startAutoScrollIfNecessary` now consults
`scrollable.resolvedPhysics.shouldAcceptUserOffset(scrollable.position)`.
If physics refuses user offset, it `stopAutoScroll()`s and returns early
— mirroring the pattern at the existing guard sites. No new public API.

The auto-scroller is shared infrastructure: `SliverReorderableList` uses
the same `startAutoScrollIfNecessary` for drag-reorder auto-scroll.
Under default physics the new guard is a pass-through, so reorder
behavior is unchanged; the existing `SliverReorderableList auto scrolls
speed is configurable` test serves as the regression guard and still
passes.

## Test

Added a `testWidgets` in `scrollable_selection_test.dart` that
mouse-drag-selects past the bottom of a `ListView` wrapped in a
`SelectionArea` with `NeverScrollableScrollPhysics`, then asserts the
scroll offset stays at `0.0` and no exception is thrown. The new test
fails on `master` with `Expected: <0.0> Actual: <20.0>` and passes with
this change.

## Manual verification

Tested with the original repro (a `SelectionArea` >
`PageView(NeverScrollableScrollPhysics)` with a `DataTable` first page
and a `Text` second page). Before: drag-selecting near the right edge of
the DataTable slid the PageView to page 2 and threw the assertion.
After: PageView stays on page 1 and selection continues normally. Video
attached.



https://github.com/user-attachments/assets/c2d07063-50ca-445a-b712-362e07c7d84b



## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [AI contribution guidelines] and understand my
responsibilities, or I am not using AI tools.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [ ] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

If this change needs to override an active code freeze, provide a
comment explaining why. The code freeze workflow can be overridden by
code reviewers. See pinned issues for any active code freezes with
guidance.

**Note**: The Flutter team is currently trialing the use of [Gemini Code
Assist for
GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code).
Comments from the `gemini-code-assist` bot should not be taken as
authoritative feedback from the Flutter team. If you find its comments
useful you can update your code accordingly, but if you are unsure or
disagree with the feedback, please feel free to wait for a Flutter team
member's review for guidance on which automated comments should be
addressed.

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[AI contribution guidelines]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md

---------

Co-authored-by: Navaron Bracke <brackenavaron@gmail.com>
creatorpiyush pushed a commit to creatorpiyush/packages that referenced this pull request Jun 10, 2026
…r#11747)

flutter/flutter@259aeae...e03b91f

2026-05-20 engine-flutter-autoroll@skia.org Roll Packages from ade10ca to 1dfbada (6 revisions) (flutter/flutter#186811)
2026-05-20 brunocorona.alcantar@gmail.com Fix AnimatedList.separated assert when removing last item mid-removal… (flutter/flutter#186389)
2026-05-20 engine-flutter-autoroll@skia.org Roll Skia from d45969a5752e to 5f4f454b9662 (2 revisions) (flutter/flutter#186809)
2026-05-20 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from -F9Ci3Opxt06MixDl... to iKCvaD58jKStYGla0... (flutter/flutter#186796)
2026-05-20 engine-flutter-autoroll@skia.org Roll Skia from 19ad9707e5c6 to d45969a5752e (2 revisions) (flutter/flutter#186792)
2026-05-20 engine-flutter-autoroll@skia.org Roll Skia from 3471ebf5af0c to 19ad9707e5c6 (9 revisions) (flutter/flutter#186772)
2026-05-20 mdebbar@google.com [web] Refactor webparagraph painters to separate CK properly (flutter/flutter#186684)
2026-05-19 31859944+LongCatIsLooong@users.noreply.github.com Enable Swift testing in the iOS embedder (flutter/flutter#185712)
2026-05-19 mdebbar@google.com [web] Rename WebParagraph goldens (flutter/flutter#186680)
2026-05-19 engine-flutter-autoroll@skia.org Roll Skia from f1b406860c5e to 3471ebf5af0c (5 revisions) (flutter/flutter#186745)
2026-05-19 154381524+flutteractionsbot@users.noreply.github.com Revert "Ship gen_snapshot for linux-arm64 hosts targeting Android" (flutter/flutter#186693)
2026-05-19 bkonyi@google.com [ Tool ] Remove legacy analytics code (flutter/flutter#184994)
2026-05-19 chingjun@google.com Update Vulkan enum values (flutter/flutter#186694)
2026-05-19 1961493+harryterkelsen@users.noreply.github.com fix(web): Fixes CSS override detection when the browser has a default font size (flutter/flutter#186474)
2026-05-19 30870216+gaaclarke@users.noreply.github.com adds linux impeller hello world integration test (flutter/flutter#186715)
2026-05-19 jason-simmons@users.noreply.github.com Update the list of binaries in the code signing verification test to include new Dart snapshots (flutter/flutter#186754)
2026-05-19 brunocorona.alcantar@gmail.com Make EdgeDraggingAutoScroller respect ScrollPhysics (flutter/flutter#186541)
2026-05-19 bkonyi@google.com [ Widget Preview ] Fix inspector split resize focus loss over WebViews (flutter/flutter#186432)
2026-05-19 engine-flutter-autoroll@skia.org Roll Packages from b9bdd37 to ade10ca (1 revision) (flutter/flutter#186746)
2026-05-19 jason-simmons@users.noreply.github.com Manual Dart roll from 8e30b88e4d5a to 66873d2da857 (flutter/flutter#186690)
2026-05-19 bkonyi@google.com [ Widget Preview ] Improve zoom behavior and add zoom slider (flutter/flutter#186422)

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 stuartmorgan@google.com 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
via-guy pushed a commit to via-guy/flutter that referenced this pull request Jun 26, 2026
Fixes flutter#140654

## Problem

When a `Scrollable` with `NeverScrollableScrollPhysics` lives under a
`SelectionArea`, drag-selecting past the edge of the viewport still
auto-scrolls it, and can additionally trip the *"Drag target size is
larger than scrollable size, which may cause bouncing"* assertion in
`scrollable_helpers.dart`. The original report uses a `PageView(physics:
NeverScrollableScrollPhysics())` containing a `DataTable`; reproduces on
web, macOS, and Android, back to 3.16.

## Root cause

`EdgeDraggingAutoScroller._scroll()` advances the scroll position by
calling `ScrollPosition.animateTo(...)` directly. That bypasses
`ScrollPhysics.applyUserOffset` / `applyBoundaryConditions`, so a
`Scrollable` whose physics returns `false` from `shouldAcceptUserOffset`
was still being driven during a drag-select. The two other user-driven
scroll entry points already had this guard — `ScrollAction.invoke` in
`scrollable_helpers.dart` and `Scrollable._receivedPointerSignal` in
`scrollable.dart` — the auto-scroller was the missing one. The assertion
lives inside `_scroll()`, so it fires only because `_scroll()` runs when
it shouldn't; gating physics resolves both symptoms in one place.

(Root cause originally diagnosed by @Renzo-Olivares on the issue thread)

## Change

`EdgeDraggingAutoScroller.startAutoScrollIfNecessary` now consults
`scrollable.resolvedPhysics.shouldAcceptUserOffset(scrollable.position)`.
If physics refuses user offset, it `stopAutoScroll()`s and returns early
— mirroring the pattern at the existing guard sites. No new public API.

The auto-scroller is shared infrastructure: `SliverReorderableList` uses
the same `startAutoScrollIfNecessary` for drag-reorder auto-scroll.
Under default physics the new guard is a pass-through, so reorder
behavior is unchanged; the existing `SliverReorderableList auto scrolls
speed is configurable` test serves as the regression guard and still
passes.

## Test

Added a `testWidgets` in `scrollable_selection_test.dart` that
mouse-drag-selects past the bottom of a `ListView` wrapped in a
`SelectionArea` with `NeverScrollableScrollPhysics`, then asserts the
scroll offset stays at `0.0` and no exception is thrown. The new test
fails on `master` with `Expected: <0.0> Actual: <20.0>` and passes with
this change.

## Manual verification

Tested with the original repro (a `SelectionArea` >
`PageView(NeverScrollableScrollPhysics)` with a `DataTable` first page
and a `Text` second page). Before: drag-selecting near the right edge of
the DataTable slid the PageView to page 2 and threw the assertion.
After: PageView stays on page 1 and selection continues normally. Video
attached.



https://github.com/user-attachments/assets/c2d07063-50ca-445a-b712-362e07c7d84b



## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [AI contribution guidelines] and understand my
responsibilities, or I am not using AI tools.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [ ] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

If this change needs to override an active code freeze, provide a
comment explaining why. The code freeze workflow can be overridden by
code reviewers. See pinned issues for any active code freezes with
guidance.

**Note**: The Flutter team is currently trialing the use of [Gemini Code
Assist for
GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code).
Comments from the `gemini-code-assist` bot should not be taken as
authoritative feedback from the Flutter team. If you find its comments
useful you can update your code accordingly, but if you are unsure or
disagree with the feedback, please feel free to wait for a Flutter team
member's review for guidance on which automated comments should be
addressed.

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[AI contribution guidelines]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md

---------

Co-authored-by: Navaron Bracke <brackenavaron@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD 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.

PageView with SelectionArea scrolls even with NeverScrollablePhysics and throws an Exception

4 participants