-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Add onReorderUpdate callback to ReorderableListView
#172738
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add onReorderUpdate callback to ReorderableListView
#172738
Conversation
|
It looks like this pull request may not have tests. Please make sure to add tests or get an explicit test exemption before merging. If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix? Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.If you believe this PR qualifies for a test exemption, contact "@test-exemption-reviewer" in the #hackers channel in Discord (don't just cc them here, they won't see it!). The test exemption team is a small volunteer group, so all reviewers should feel empowered to ask for tests, without delegating that responsibility entirely to the test exemption group. |
1c1966c to
a7e06c2
Compare
6ede3a1 to
b1e969d
Compare
onReorderUpdate callback to ReorderableList
onReorderUpdate callback to ReorderableListonReorderUpdate callback to ReorderableListView
99dbb74 to
6aba260
Compare
0b6af15 to
e8c013f
Compare
Adds onReorderUpdate callback to ReorderableListView that fires continuously during drag operations when the potential insertion position changes. The callback provides final indices accounting for Flutter's quirk where the index represents the pending insertion point before removal, rather than the would-be destination index after the reorder.
e8c013f to
76b6a57
Compare
|
To do:
|
|
This one as well - I run through older PRs every week to make sure we aren't missing any in our other triage meetings, so no pressure at all. Just checking in. :) |
|
@Piinks Thanks for the messages, I totally understand and appreciate the check-ins! For now I'm going to close these drafts; I think these are valuable enhancements—to the extent that I've vendored the framework files and implemented them in my own app—but I think they're too niche to justify the effort needed to make their PRs merge-worthy. Happy to revisit someday if it makes sense though ☀️ Thanks for all you do Kate! |
…animation (#173241) When rapidly dragging items in a ReorderableList before animations complete, items would jump to their expected positions rather than smoothly transitioning. ## Problem <p align="center"> <img src="https://github.com/user-attachments/assets/0efb250c-2960-4942-959f-59eccc20cefb" alt="demo2" width="250"> </p> The issue occurs when a reorder animation is interrupted by starting a new drag operation. The interrupted animation would reset to the starting position of the original animation rather than capturing the current animated position, causing a visual jump. ## Solution This PR fixes the issue by: 1. Storing the previous target offset before updating to a new target 2. When an animation is interrupted, calculating the actual current position based on the animation's progress 3. Using this calculated position as the new starting point for the next animation <p align="center"> <img src="https://github.com/user-attachments/assets/c24e4834-1c6b-41c1-8f44-17b4c79e0993" alt="demo2" width="250"> </p> This PR is part of a series of `ReorderableList` enhancements I've developed for [TimeFinder](https://timefinder.app): - #172740 - #172380 - #172739 - #172738 Fixes #173243 ## Code Changes ```dart // Before _startOffset = offset; // After final double currentAnimValue = Curves.easeInOut.transform(_offsetAnimation\!.value); final Offset currentPosition = Offset.lerp(_startOffset, previousTarget, currentAnimValue)\!; _startOffset = currentPosition; ``` This ensures smooth transitions without visual jumping, making rapid reordering gestures feel more responsive and natural. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [migration guide] as needed. - [x] All existing and new tests are passing. - [x] The analyzer (`flutter analyze --flutter-repo`) does not report any problems on my PR. - [x] I am willing to follow-up on review comments in a timely manner. [Contributor Guide]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md [Flutter Style Guide]: https://github.com/flutter/flutter/blob/master/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/master/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [test-exempt]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#tests [breaking change policy]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#handling-breaking-changes [migration guide]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#create-a-migration-guide
…animation (flutter#173241) When rapidly dragging items in a ReorderableList before animations complete, items would jump to their expected positions rather than smoothly transitioning. ## Problem <p align="center"> <img src="https://github.com/user-attachments/assets/0efb250c-2960-4942-959f-59eccc20cefb" alt="demo2" width="250"> </p> The issue occurs when a reorder animation is interrupted by starting a new drag operation. The interrupted animation would reset to the starting position of the original animation rather than capturing the current animated position, causing a visual jump. ## Solution This PR fixes the issue by: 1. Storing the previous target offset before updating to a new target 2. When an animation is interrupted, calculating the actual current position based on the animation's progress 3. Using this calculated position as the new starting point for the next animation <p align="center"> <img src="https://github.com/user-attachments/assets/c24e4834-1c6b-41c1-8f44-17b4c79e0993" alt="demo2" width="250"> </p> This PR is part of a series of `ReorderableList` enhancements I've developed for [TimeFinder](https://timefinder.app): - flutter#172740 - flutter#172380 - flutter#172739 - flutter#172738 Fixes flutter#173243 ## Code Changes ```dart // Before _startOffset = offset; // After final double currentAnimValue = Curves.easeInOut.transform(_offsetAnimation\!.value); final Offset currentPosition = Offset.lerp(_startOffset, previousTarget, currentAnimValue)\!; _startOffset = currentPosition; ``` This ensures smooth transitions without visual jumping, making rapid reordering gestures feel more responsive and natural. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [migration guide] as needed. - [x] All existing and new tests are passing. - [x] The analyzer (`flutter analyze --flutter-repo`) does not report any problems on my PR. - [x] I am willing to follow-up on review comments in a timely manner. [Contributor Guide]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md [Flutter Style Guide]: https://github.com/flutter/flutter/blob/master/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/master/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [test-exempt]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#tests [breaking change policy]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#handling-breaking-changes [migration guide]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#create-a-migration-guide
…animation (flutter#173241) When rapidly dragging items in a ReorderableList before animations complete, items would jump to their expected positions rather than smoothly transitioning. ## Problem <p align="center"> <img src="https://github.com/user-attachments/assets/0efb250c-2960-4942-959f-59eccc20cefb" alt="demo2" width="250"> </p> The issue occurs when a reorder animation is interrupted by starting a new drag operation. The interrupted animation would reset to the starting position of the original animation rather than capturing the current animated position, causing a visual jump. ## Solution This PR fixes the issue by: 1. Storing the previous target offset before updating to a new target 2. When an animation is interrupted, calculating the actual current position based on the animation's progress 3. Using this calculated position as the new starting point for the next animation <p align="center"> <img src="https://github.com/user-attachments/assets/c24e4834-1c6b-41c1-8f44-17b4c79e0993" alt="demo2" width="250"> </p> This PR is part of a series of `ReorderableList` enhancements I've developed for [TimeFinder](https://timefinder.app): - flutter#172740 - flutter#172380 - flutter#172739 - flutter#172738 Fixes flutter#173243 ## Code Changes ```dart // Before _startOffset = offset; // After final double currentAnimValue = Curves.easeInOut.transform(_offsetAnimation\!.value); final Offset currentPosition = Offset.lerp(_startOffset, previousTarget, currentAnimValue)\!; _startOffset = currentPosition; ``` This ensures smooth transitions without visual jumping, making rapid reordering gestures feel more responsive and natural. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [migration guide] as needed. - [x] All existing and new tests are passing. - [x] The analyzer (`flutter analyze --flutter-repo`) does not report any problems on my PR. - [x] I am willing to follow-up on review comments in a timely manner. [Contributor Guide]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md [Flutter Style Guide]: https://github.com/flutter/flutter/blob/master/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/master/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [test-exempt]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#tests [breaking change policy]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#handling-breaking-changes [migration guide]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#create-a-migration-guide
Description
This PR adds an
onReorderUpdatecallback toReorderableListViewthat fires continuously during drag operations, enabling developers to provide immediate feedback as items move between positions. This addresses a long-standing limitation where developers only had access to start/end callbacks, making it impossible to provide immediate user feedback during reordering.This video demonstrates the new
onReorderUpdatecallback, showing real-time feedback during drag operations.Motivation
Developers have long requested the ability to provide immediate feedback during reorder operations (see #139187). Currently,
ReorderableListViewonly provides callbacks at the start and end of a drag, limiting the ability to create responsive, modern UIs with haptic feedback, visual indicators, or sound effects during dragging.This PR is part of a series of
ReorderableListenhancements I've developed for TimeFinder:ReorderableListView#172740ReorderableListproxy animation for partial drag-back #172380ReorderableListitems jumping when drag direction reverses mid-animation #173241ReorderableListView#172739Usage Example
Implementation Details
API Changes
ReorderUpdateCallbacktypedef:void Function(int fromIndex, int toIndex)onReorderUpdateparameter toReorderableListView,ReorderableList, andSliverReorderableList_dragUpdateItems()whenever the potential drop position changesIndex Handling
Flutter's reordering API uses a specific convention that requires careful handling:
The Challenge: The
onReordercallback receivesnewIndexas an insertion point before the dragged item is removed from the list. For example:[A, B, C, D]onReorderreceives:oldIndex=1, newIndex=3(not 2)This convention (documented in
ReorderCallback) works fine for the finalonReordercallback but presents challenges for continuous updates where developers expect intuitive "final position" values.The Solution: This PR includes a helper method that converts insertion points to final positions:
This ensures
onReorderUpdateprovides intuitive values that match what developers expect and what they would implement in theironReorderhandler.Preventing Redundant Callbacks
The implementation tracks the previous final index to ensure callbacks only fire when the actual destination position changes, preventing unnecessary updates when the internal
_insertIndexchanges without affecting the final position.Related Issues
Resolves #139187
This addresses needs expressed in third-party packages that have attempted to work around this limitation:
Pre-launch Checklist
///).Breaking Change
Does your PR require Flutter developers to manually update their apps to accommodate your change?