-
Notifications
You must be signed in to change notification settings - Fork 28.7k
Add .separated
constructor to ReorderableListView
#168834
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
base: master
Are you sure you want to change the base?
Add .separated
constructor to ReorderableListView
#168834
Conversation
.separated
constructor to ReorderableListView
@@ -75,6 +76,8 @@ class ReorderableListView extends StatefulWidget { | ||
/// | ||
/// * [ReorderableListView.builder], which allows you to build a reorderable | ||
/// list where the items are built as needed when scrolling the list. | ||
/// * [ReorderableListView.separated], which allows you to build a reorderable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Unrelated to this PR, but this and above (ReorderableListView.builder
) should use third person instead of second person (i.e no 'you'). https://github.com/flutter/flutter/blob/master/docs/contributing/Style-guide-for-Flutter-repo.md#use-the-passive-voice-recommend-do-not-require-never-say-things-are-simple
} | ||
final int itemIndex = index ~/ 2; | ||
if (index.isEven) { | ||
// It's an item |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Here and below, I'm not sure the comments add anything not already clear from the lines of code succeeding it.
// It's an item | ||
return itemBuilder(context, itemIndex); | ||
} else { | ||
// It's a separator |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And here.
/// When using the [ReorderableListView.separated] constructor, this is the total | ||
/// number of children in the list, including items and separators. | ||
/// The actual number of data items is less. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since there is a separatorBuilder, is there a world where this only counts data items? or is this because a user might want separators only on certain indices?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think renaming it to childCount
would make more sense? I was just following the existing naming pattern. Should itemCount
be stored in the widget as well?
/// This callback is used to build the separator widgets that appear between items. | ||
/// It is called with indices from 0 to `itemCount - 2` (where `itemCount` is | ||
/// the number of actual data items). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of speculating about the data items or non-data items, can we directly reference ReorderableListView.itemCount
here (assuming an item-separator-item pattern)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Related to above question, I think it's better then to store itemCount
and childCount
separately and itemCount
can be properly referenced here.
/// It is called with indices from 0 to `itemCount - 2` (where `itemCount` is | ||
/// the number of actual data items). | ||
/// | ||
/// Will be null if not using the `separated` constructor. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Will be null if not using the `separated` constructor. | |
/// Null if this is not a `ReorderableListView.separated`. |
or something similar.
/// Will be null if not using the `separated` constructor. | ||
final IndexedWidgetBuilder? separatorBuilder; | ||
|
||
/// Helper method to compute the actual child count for the separated constructor. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Helper method to compute the actual child count for the separated constructor. | |
/// Helper method to compute the actual child count for a `ReorderableListView.separated`. |
Prefer the actual reference over a (possibly) vague allusion.
// If using .separated, separators are at odd indices. | ||
// We only want drag handles and specific keys for actual items (even indices). | ||
final bool isSeparator = widget.separatorBuilder != null && index.isOdd; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels odd (no pun intended). Does this break down if a user has their separators at non-regular intervals?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current implementation enforces a regular pattern where separators must appear between every item. This is by design and matches the behavior of ListView.separated
. If users need non-regular separators, they should use the regular ReorderableListView
or ReorderableListView.builder
constructors and handle the separators manually in their item builder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation for the constructor should contain this info if it doesn't already.
@victorsanni Thanks for the detailed review ! I tried to address all of your concerns, please have another look 🙇 |
itemCount = children.length, | ||
childCount = children.length, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note
Keep separated track of itemCount
and childCount
. itemCount
is used in the default constructor and .builder
constructor. .seperated
constructor requires additional property childCount
to keep track of combined count of items + divider.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see ListView.separated does something similar with what you had previously (using itemCount etc). I first blind-reviewed but now I see the implementation aims to be almost identical to ListView.separated
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can I confirm with you if you say I should revert my changes and exclusively use itemCount
? Or is it okay to continue having separate variables for itemCount
and childCount
? Later one makes technical more sense to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is that childCount is defined and calculated but never used. If childCount does not modify the behavior of this widget, then it shouldn't be added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for responding! Can you also attach videos/screenshots to the PR description comparing before/after? This will make the PR easier to review.
The example and tests are also really nice. For now, can you attach the example code to the PR description, and add the example/example test in a subsequent PR? The leaner the PR, the easier it is to review.
Thanks once again.
itemCount = children.length, | ||
childCount = children.length, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see ListView.separated does something similar with what you had previously (using itemCount etc). I first blind-reviewed but now I see the implementation aims to be almost identical to ListView.separated
.
// If using .separated, separators are at odd indices. | ||
// We only want drag handles and specific keys for actual items (even indices). | ||
final bool isSeparator = widget.separatorBuilder != null && index.isOdd; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation for the constructor should contain this info if it doesn't already.
@@ -143,7 +148,7 @@ class ReorderableListView extends StatefulWidget { | ||
/// {@end-tool} | ||
/// See also: | ||
/// | ||
/// * [ReorderableListView], which allows you to build a reorderable | ||
/// * [ReorderableListView], which allows one to build a reorderable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// * [ReorderableListView], which allows one to build a reorderable | |
/// * [ReorderableListView], which builds a reorderable |
Or something similar. But this is a nit, feel free to edit.
/// number of children in the list, including items and separators. | ||
/// When using [ReorderableListView] or the [ReorderableListView.builder] constructor, this is the number of items | ||
/// in the list. | ||
final int childCount; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't think this property should be added.
/// The number of data items in the list. | ||
/// | ||
/// This is the number of data items in the list, not the number of children. | ||
/// For example, if there is a list with 10 items and 9 separators, this will be 10. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is custom, then the macro should be removed. You can combine the information in here with what the macro already has with something like this:
/// The number of data items in the list.
///
/// If this widget is a ReorderableListView.separated, {insert docs for special case}
///
/// This value must be a non-negative integer. When zero, nothing is displayed and
/// the widget occupies no space.
final double? itemExtent; | ||
|
||
/// {@macro flutter.widgets.list_view.itemExtentBuilder} | ||
/// This is not used by the [ReorderableListView.separated] constructor. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// This is not used by the [ReorderableListView.separated] constructor. | |
/// | |
/// Null if this is a [ReorderableListView.separated]. |
final ItemExtentBuilder? itemExtentBuilder; | ||
|
||
/// {@macro flutter.widgets.list_view.prototypeItem} | ||
/// This is not used by the [ReorderableListView.separated] constructor. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// This is not used by the [ReorderableListView.separated] constructor. | |
/// | |
/// Null if this is a [ReorderableListView.separated]. |
/// Helper method to compute the actual child count for [ReorderableListView.separated]. | ||
static int _computeActualChildCount(int itemCount) { | ||
return math.max(0, itemCount * 2 - 1); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure this method is needed or used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is needed to calculate the total child length based on amount of items and the necessary dividers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The method is only used here to calculate childCount, but childCount is never used as far as I can see. Could I be missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You suggest to remove childCount
and consolidate it with itemCount
. For calculation of itemCount
we would still need the method to properly count the total items (items + divider count). Am I completely misunderstanding what you mean?
Or do you mean it is not necessary to combine divider count + item count into itemCount
so that itemCount
should just be the number of items (exclusive dividers). I didn't consider that so far, cause I'm not sure if it plays internally a role.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I searched in this file for childCount
. I saw it was added as a property, and it was also updated here:
childCount = _computeActualChildCount(itemCount),
but I can't find where it is actually used/referenced.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You suggest to remove childCount and consolidate it with itemCount. For calculation of itemCount we would still need the method to properly count the total items (items + divider count). Am I completely misunderstanding what you mean?
If the method is needed to calculate itemCount
, then it should be used to do that. But right now I don't see it being used to calculate itemCount
, only childCount
.
This PR introduces a
.separated
constructor to theReorderableListView
widget. The.separated
constructor allows developers to define custom separators between the list items without the need to manually modify their list or create custom widgets. This API enhancement improves the overall usability and flexibility ofReorderableListView
.Key Changes:
.separated
constructor toReorderableListView
..separated
functionality.This new feature addresses the requests in issue #76706.
Pre-launch Checklist
///
).If you need help, consider asking for advice on the #hackers-new channel on Discord.
Video
separated_example.mp4