From 25388383062cb84c7ab42050471b19ed119e4e0a Mon Sep 17 00:00:00 2001 From: Navaron Bracke Date: Fri, 30 Jan 2026 23:51:07 +0100 Subject: [PATCH 1/5] add onReorder callback migration guide --- .../deprecate-onreorder-callback.md | 186 ++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 src/content/release/breaking-changes/deprecate-onreorder-callback.md diff --git a/src/content/release/breaking-changes/deprecate-onreorder-callback.md b/src/content/release/breaking-changes/deprecate-onreorder-callback.md new file mode 100644 index 0000000000..4082ec40d4 --- /dev/null +++ b/src/content/release/breaking-changes/deprecate-onreorder-callback.md @@ -0,0 +1,186 @@ +--- +title: Deprecate onReorder callback +description: >- + The `onReorder` callback has been deprecated + in favor of a new callback, called `onReorderItem`. +--- + +{% render "docs/breaking-changes.md" %} + +## Summary + +The `onReorder` callback in the `ReorderableListView`, +`ReorderableListView.builder`, `ReorderableList` and `SliverReorderableList` +widgets has been replaced by a new callback, `onReorderItem` +to fix the confusing behavior of the second callback parameter, `newIndex`. + +## Background + +The `onReorder` callback in the `ReorderableListView`, +`ReorderableListView.builder`, `ReorderableList` and `SliverReorderableList` +widgets used to require a manual correction +for the second parameter, `newIndex`, +in case the `oldIndex` is before the `newIndex`, +due to the list of items shortening by one element in this case. + +```dart +void handleReorder(int oldIndex, int newIndex) { + if (oldIndex < newIndex) { + // removing the item at oldIndex will shorten the list by 1. + newIndex -= 1; + } + + // handle the actual reorder behavior... +} + +ReorderableListView( + onReorder: handleReorder, +) +``` + +The new callback, `onReorderItem`, aims to solve this problem, +by doing the correction automatically. + +```dart +void handleReorder(int oldIndex, int newIndex) { + // handle the actual reorder behavior... +} + +ReorderableListView( + onReorderItem: handleReorder, +) +``` + +## Migration guide + +First, rename the `onReorder` callback parameter in any `ReorderableListView`, +`ReorderableListView.builder`, `ReorderableList` and `SliverReorderableList` +widget constructors, to `onReorderItem`. + +Then, in the callback that is passed to `onReorderItem`, +remove the if-case that corrects the second function parameter, +if it is larger than the first function parameter, +since it is no longer needed. + +This migration is not supported by `dart fix`, +due to the change in meaning for the second callback parameter. + +Code before migration: + +```dart +ReorderableListView( + onReorder: (int oldIndex, int newIndex) { + if (oldIndex < newIndex) { + newIndex -= 1; + } + + // Handle reorder ... + } +) +``` + +```dart +ReorderableListView.builder( + onReorder: (int oldIndex, int newIndex) { + if (oldIndex < newIndex) { + newIndex -= 1; + } + + // Handle reorder ... + } +) +``` + +```dart +ReorderableList( + onReorder: (int oldIndex, int newIndex) { + if (oldIndex < newIndex) { + newIndex -= 1; + } + + // Handle reorder ... + } +) +``` + +```dart +SliverReorderableList( + onReorder: (int oldIndex, int newIndex) { + if (oldIndex < newIndex) { + newIndex -= 1; + } + + // Handle reorder ... + } +) +``` + +Code after migration: + +```dart +ReorderableListView( + onReorderItem: (int oldIndex, int newIndex) { + // Handle reorder ... + } +) +``` + +```dart +ReorderableListView.builder( + onReorderItem: (int oldIndex, int newIndex) { + // Handle reorder ... + } +) +``` + +```dart +ReorderableList( + onReorderItem: (int oldIndex, int newIndex) { + // Handle reorder ... + } +) +``` + +```dart +SliverReorderableList( + onReorderItem: (int oldIndex, int newIndex) { + // Handle reorder ... + } +) +``` + +## Timeline + +Landed in version: 3.41.0-1.0.pre-364
+In stable release: Not yet + +## References + +{% render "docs/main-api.md", site: site %} + +API documentation: + +* [`ReorderCallback`][] +* [`ReorderableList`][] +* [`ReorderableListView`][] +* [`SliverReorderableList`][] + +Relevant issues: + +* [Issue 127901][] +* [Issue 169878][] + +Relevant PRs: + +* [Deprecate onReorder callback][] + +{% render "docs/main-api.md", site: site %} + +[`ReorderCallback`]: {{site.main-api}}/flutter/widgets/ReorderCallback.html +[`ReorderableList`]: {{site.main-api}}/flutter/widgets/ReorderableList-class.html +[`ReorderableListView`]: {{site.main-api}}/flutter/material/ReorderableListView-class.html +[`SliverReorderableList`]: {{site.main-api}}/flutter/widgets/SliverReorderableList-class.html + +[Issue 127901]: {{site.repo.flutter}}/issues/127901 +[Issue 169878]: {{site.repo.flutter}}/issues/169878 +[Deprecate onReorder callback]: {{site.repo.flutter}}/pull/178242 \ No newline at end of file From e3f7dba93e6ce0343429e6b3b8abe51b2a7c581a Mon Sep 17 00:00:00 2001 From: Navaron Bracke Date: Sat, 31 Jan 2026 20:07:15 +0100 Subject: [PATCH 2/5] review feedback --- .../deprecate-onreorder-callback.md | 51 ++++++++++++------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/src/content/release/breaking-changes/deprecate-onreorder-callback.md b/src/content/release/breaking-changes/deprecate-onreorder-callback.md index 4082ec40d4..c8c1534f23 100644 --- a/src/content/release/breaking-changes/deprecate-onreorder-callback.md +++ b/src/content/release/breaking-changes/deprecate-onreorder-callback.md @@ -11,8 +11,8 @@ description: >- The `onReorder` callback in the `ReorderableListView`, `ReorderableListView.builder`, `ReorderableList` and `SliverReorderableList` -widgets has been replaced by a new callback, `onReorderItem` -to fix the confusing behavior of the second callback parameter, `newIndex`. +widgets has been replaced by a new callback, `onReorderItem`, +which provides a more intuitive behavior on index. ## Background @@ -53,18 +53,6 @@ ReorderableListView( ## Migration guide -First, rename the `onReorder` callback parameter in any `ReorderableListView`, -`ReorderableListView.builder`, `ReorderableList` and `SliverReorderableList` -widget constructors, to `onReorderItem`. - -Then, in the callback that is passed to `onReorderItem`, -remove the if-case that corrects the second function parameter, -if it is larger than the first function parameter, -since it is no longer needed. - -This migration is not supported by `dart fix`, -due to the change in meaning for the second callback parameter. - Code before migration: ```dart @@ -115,6 +103,22 @@ SliverReorderableList( ) ``` +```dart +void handleReorder(int oldIndex, int newIndex) { + if (oldIndex < newIndex) { + newIndex -= 1; + } + + // Handle reorder ... +} + +ReorderableListView( + onReorder: (int oldIndex, int newIndex) { + return handleReorder(oldIndex, newIndex); + } +) +``` + Code after migration: ```dart @@ -149,6 +153,21 @@ SliverReorderableList( ) ``` +```dart +void handleReorder(int oldIndex, int newIndex) { + // Handle reorder ... +} + +ReorderableListView( + onReorderItem: (int oldIndex, int newIndex) { + return handleReorder(oldIndex, newIndex); + } +) +``` + +This migration is not supported by `dart fix`, +due to the change in meaning for the second callback parameter. + ## Timeline Landed in version: 3.41.0-1.0.pre-364
@@ -156,8 +175,6 @@ In stable release: Not yet ## References -{% render "docs/main-api.md", site: site %} - API documentation: * [`ReorderCallback`][] @@ -174,8 +191,6 @@ Relevant PRs: * [Deprecate onReorder callback][] -{% render "docs/main-api.md", site: site %} - [`ReorderCallback`]: {{site.main-api}}/flutter/widgets/ReorderCallback.html [`ReorderableList`]: {{site.main-api}}/flutter/widgets/ReorderableList-class.html [`ReorderableListView`]: {{site.main-api}}/flutter/material/ReorderableListView-class.html From c21593a13e51742c5de469923b613f46b7c92833 Mon Sep 17 00:00:00 2001 From: Navaron Bracke Date: Tue, 3 Feb 2026 20:23:14 +0100 Subject: [PATCH 3/5] more feedback + formatting fixes --- .../deprecate-onreorder-callback.md | 177 ++++++++++-------- 1 file changed, 94 insertions(+), 83 deletions(-) diff --git a/src/content/release/breaking-changes/deprecate-onreorder-callback.md b/src/content/release/breaking-changes/deprecate-onreorder-callback.md index c8c1534f23..cea502595f 100644 --- a/src/content/release/breaking-changes/deprecate-onreorder-callback.md +++ b/src/content/release/breaking-changes/deprecate-onreorder-callback.md @@ -1,8 +1,8 @@ --- title: Deprecate onReorder callback description: >- - The `onReorder` callback has been deprecated - in favor of a new callback, called `onReorderItem`. + The onReorder callback has been deprecated + in favor of a new callback, called onReorderItem. --- {% render "docs/breaking-changes.md" %} @@ -25,16 +25,16 @@ due to the list of items shortening by one element in this case. ```dart void handleReorder(int oldIndex, int newIndex) { - if (oldIndex < newIndex) { - // removing the item at oldIndex will shorten the list by 1. - newIndex -= 1; - } + if (oldIndex < newIndex) { + // Removing the item at oldIndex will shorten the list by 1. + newIndex -= 1; + } - // handle the actual reorder behavior... + // Handle the actual reorder behavior... } ReorderableListView( - onReorder: handleReorder, + onReorder: handleReorder, ) ``` @@ -43,130 +43,141 @@ by doing the correction automatically. ```dart void handleReorder(int oldIndex, int newIndex) { - // handle the actual reorder behavior... + // handle the actual reorder behavior... } ReorderableListView( - onReorderItem: handleReorder, + onReorderItem: handleReorder, ) ``` ## Migration guide +The `ReorderableListView`, `ReorderableListView.builder`, +`ReorderableList` and `SliverReorderableList` widgets +share the same reordering logic, the migration steps +are identical for any of these widgets. + +For the purpose of this migration guide, +`ReorderableListView` is chosen as an example. + +### Case 1: trivial case + Code before migration: ```dart ReorderableListView( - onReorder: (int oldIndex, int newIndex) { - if (oldIndex < newIndex) { - newIndex -= 1; - } - - // Handle reorder ... + onReorder: (int oldIndex, int newIndex) { + if (oldIndex < newIndex) { + newIndex -= 1; } -) -``` - -```dart -ReorderableListView.builder( - onReorder: (int oldIndex, int newIndex) { - if (oldIndex < newIndex) { - newIndex -= 1; - } - // Handle reorder ... - } + // Handle reorder ... + } ) ``` -```dart -ReorderableList( - onReorder: (int oldIndex, int newIndex) { - if (oldIndex < newIndex) { - newIndex -= 1; - } +Code after migration: - // Handle reorder ... +```dart diff + ReorderableListView( +- onReorder: (int oldIndex, int newIndex) { +- if (oldIndex < newIndex) { +- newIndex -= 1; +- } +- ++ onReorderItem: (int oldIndex, int newIndex) { + // Handle reorder ... } -) + ) ``` -```dart -SliverReorderableList( - onReorder: (int oldIndex, int newIndex) { - if (oldIndex < newIndex) { - newIndex -= 1; - } +### Case 2: using a separate callback - // Handle reorder ... - } -) -``` +Code before migration: ```dart void handleReorder(int oldIndex, int newIndex) { - if (oldIndex < newIndex) { - newIndex -= 1; - } + if (oldIndex < newIndex) { + newIndex -= 1; + } - // Handle reorder ... + // Handle reorder ... } ReorderableListView( - onReorder: (int oldIndex, int newIndex) { - return handleReorder(oldIndex, newIndex); - } + onReorder: (int oldIndex, int newIndex) { + return handleReorder(oldIndex, newIndex); + } ) ``` Code after migration: -```dart -ReorderableListView( - onReorderItem: (int oldIndex, int newIndex) { - // Handle reorder ... - } -) -``` +```dart diff + void handleReorder(int oldIndex, int newIndex) { +- if (oldIndex < newIndex) { +- newIndex -= 1; +- } +- + // Handle reorder ... + } -```dart -ReorderableListView.builder( - onReorderItem: (int oldIndex, int newIndex) { - // Handle reorder ... + ReorderableListView( +- onReorder: (int oldIndex, int newIndex) { ++ onReorderItem: (int oldIndex, int newIndex) { + return handleReorder(oldIndex, newIndex); } -) + ) ``` -```dart -ReorderableList( - onReorderItem: (int oldIndex, int newIndex) { - // Handle reorder ... - } -) -``` +### Case 3: opting out, for complex onReorder implementations -```dart -SliverReorderableList( - onReorderItem: (int oldIndex, int newIndex) { - // Handle reorder ... - } -) -``` +In some cases, it might not be obvious how to do the migration +to the new `onReorderItem` callback, +particularly if the provided callback is very complex. + +In that case, to opt out of the new behavior, +adjust the `newIndex` to match the old behavior. + +Code before migration: ```dart -void handleReorder(int oldIndex, int newIndex) { - // Handle reorder ... +void handleSomeComplexReorder(int oldIndex, int newIndex) { + // Handle reorder ... } ReorderableListView( - onReorderItem: (int oldIndex, int newIndex) { - return handleReorder(oldIndex, newIndex); - } + onReorder: (int oldIndex, int newIndex) { + handleSomeComplexReorder(oldIndex, newIndex); + } ) ``` +Code after migration: + +```dart diff + void handleSomeComplexReorder(int oldIndex, int newIndex) { + // Handle reorder ... + } + + ReorderableListView( +- onReorder: (int oldIndex, int newIndex) { ++ onReorderItem: (int oldIndex, int newIndex) { ++ // To get the equivalent of the old newIndex: ++ if (oldIndex < newIndex) { ++ newIndex += 1; ++ } ++ + return handleSomeComplexReorder(oldIndex, newIndex); + } + ) +``` + +:::important This migration is not supported by `dart fix`, due to the change in meaning for the second callback parameter. +::: ## Timeline From 0fca5db2339e6dd2ab0cc0143d5e551d9486646b Mon Sep 17 00:00:00 2001 From: Navaron Bracke Date: Wed, 4 Feb 2026 00:10:29 +0100 Subject: [PATCH 4/5] remove trivial case --- .../deprecate-onreorder-callback.md | 41 +------------------ 1 file changed, 1 insertion(+), 40 deletions(-) diff --git a/src/content/release/breaking-changes/deprecate-onreorder-callback.md b/src/content/release/breaking-changes/deprecate-onreorder-callback.md index cea502595f..6d21f94515 100644 --- a/src/content/release/breaking-changes/deprecate-onreorder-callback.md +++ b/src/content/release/breaking-changes/deprecate-onreorder-callback.md @@ -92,46 +92,7 @@ Code after migration: ) ``` -### Case 2: using a separate callback - -Code before migration: - -```dart -void handleReorder(int oldIndex, int newIndex) { - if (oldIndex < newIndex) { - newIndex -= 1; - } - - // Handle reorder ... -} - -ReorderableListView( - onReorder: (int oldIndex, int newIndex) { - return handleReorder(oldIndex, newIndex); - } -) -``` - -Code after migration: - -```dart diff - void handleReorder(int oldIndex, int newIndex) { -- if (oldIndex < newIndex) { -- newIndex -= 1; -- } -- - // Handle reorder ... - } - - ReorderableListView( -- onReorder: (int oldIndex, int newIndex) { -+ onReorderItem: (int oldIndex, int newIndex) { - return handleReorder(oldIndex, newIndex); - } - ) -``` - -### Case 3: opting out, for complex onReorder implementations +### Case 2: opting out, for complex onReorder implementations In some cases, it might not be obvious how to do the migration to the new `onReorderItem` callback, From 9fc0db90f0f748374ae4e386437f3421069ac2f8 Mon Sep 17 00:00:00 2001 From: Navaron Bracke Date: Fri, 6 Feb 2026 09:13:22 +0100 Subject: [PATCH 5/5] update index file --- src/content/release/breaking-changes/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/content/release/breaking-changes/index.md b/src/content/release/breaking-changes/index.md index 07ce977d3c..ebe08f3f15 100644 --- a/src/content/release/breaking-changes/index.md +++ b/src/content/release/breaking-changes/index.md @@ -43,6 +43,7 @@ They're sorted by release and listed in alphabetical order: * [Migrating Flutter Android app to Android Gradle Plugin 9.0.0][] * [Material 3 tokens update][] * [Page transition builders reorganization][] +* [Deprecate onReorder callback][] [Page transition builders reorganization]: /release/breaking-changes/decouple-page-transition-builders [Merged threads on Linux]: /release/breaking-changes/linux-merged-threads @@ -53,6 +54,7 @@ They're sorted by release and listed in alphabetical order: [Deprecate `findChildIndexCallback` in favor of `findItemIndexCallback` in `ListView` and `SliverList` separated constructors]: /release/breaking-changes/separated-builder-find-child-index-callback [Migrating Flutter Android app to Android Gradle Plugin 9.0.0]: /release/breaking-changes/migrate-to-agp-9 [Material 3 tokens update]: /release/breaking-changes/material-color-utilities +[Deprecate onReorder callback]: /release/breaking-changes/deprecate-onreorder-callback ### Released in Flutter 3.38