-
Notifications
You must be signed in to change notification settings - Fork 27.7k
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
Feature: Add AnimatedList with separators #144899
Feature: Add AnimatedList with separators #144899
Conversation
I'm unsure about how to best handle Is there a better way to do this? Would it be preferred to re-implement |
// Build a separator for items that have been removed from the list. | ||
/// The widget will be used by the [AnimatedListSeparatedState.removeSeparatedItem] method's | ||
/// `separatorBuilder` parameter. | ||
Widget _buildRemovedSeparator(int item , BuildContext context, Animation<double> animation) => SizeTransition( |
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.
trivial nit: remove the extra space before the comma
// Insert the "next item" into the list model. | ||
void _insert() { | ||
final int index = _selectedItem == null ? _list.length : _list.indexOf(_selectedItem!); | ||
_list.insert(index, _nextItem++); |
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.
to make this code clearer to new programmers, i recommend increasing _nextItem separate from inserting it into the list, so it's 100% clear whether the inserted value is the pre-increment or post-increment value.
), | ||
), |
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: indentation
ErrorSummary('AnimatedListSeparated.of() called with a context that does not contain an AnimatedListSeparated.'), | ||
ErrorDescription( | ||
'No AnimatedListSeparated ancestor could be found starting' | ||
' from the context that was passed to AnimatedListSeparated.of().', |
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: we prefer having the space on the end of the line before the cut
(if this is copy/pasted from some other code, bonus points for fixing that code too)
/// This method is not supported by [AnimatedListSeparatedState]. Use [removeSeparatedItem] instead. | ||
@override | ||
void removeItem(int index, AnimatedRemovedItemBuilder builder, { Duration duration = _kDuration }) { | ||
throw Exception('Separated list items can not be removed with this method. Use removeSeparatedItem instead.'); | ||
} | ||
|
||
/// This method is not supported by [AnimatedListSeparatedState]. Use [removeAllSeparatedItems] instead. | ||
@override | ||
void removeAllItems(AnimatedRemovedItemBuilder builder, { Duration duration = _kDuration }) { | ||
throw Exception('Separated list items can not be removed with this method. Use removeAllSeparatedItems instead.'); | ||
} |
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 think this would lead to confusion. Can we instead find some way to let removeItem
be how you remove items, for consistency across the various APIs?
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.
e.g. have the superclass have an @protected
internalRemoveItem
or some such, and then have the subclasses other than this one introduce a removeItem
that just forwards everything to internalRemoveItem
?
int _computeItemIndex(int index) { | ||
if (index == 0) { | ||
return index; | ||
} else { |
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.
avoid else after return
/// | ||
/// [AnimatedListSeparated] item input handlers can also refer to their [AnimatedListSeparatedState] | ||
/// with the static [AnimatedListSeparated.of] method. | ||
class AnimatedListSeparatedState extends _AnimatedScrollViewState<AnimatedListSeparated> { |
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.
@goderbauer / @Piinks
We probably shouldn't do it in this PR but the fact that we couldn't implement AnimatedListSeparatedState outside of the framework because _AnimatedScrollViewState is private probably means we have some magic here and should consider making _AnimatedScrollViewState public.
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.
Hi @Peetee06 welcome! Thanks very much for contributing.
Rather than a new class, we would typically approach this with a special constructor in the existing AnimatedList class. The ListView widget is a good example of this, with its ListView.separated constructor. There is a fair bit of duplicated code between the AnimatedListSeparated here and the AnimatedList that already exists in the framework, which would mean we need to maintain both, ensuring when we fix a bug in one class, we remember to go fix it as well in the other class, and so on.
Would you be interested in implementing this feature in the existing class?
Hi @Piinks, that was actually the first thing I tried, but I wasn't able to find a solution for the I like @Hixie's suggestion about replacing the superclass's removeItem with a protected member to be able to implement both a I would be happy to improve the code so that it has a clean, developer-friendly API. |
Would the removal of the separators just be expected by the user without having to call it themselves? I feel like that's what I would expect. In that case, we could just internally remove the leftover separators when items are removed. Maybe the constructor can have the user provide the add and remove builders just for the separators then? |
I think these are great avenues to explore, thanks for working on this! :) |
@Peetee06 is this ready for another review? |
@Piinks yes! I wrote a few infos about it and two different branches with other possible solutions in the "hackers-new" channel on discord. Here is a summary: All in all, we now have 3 possible solutions: Use @Protected internal methods for _AnimatedScrollViewState and pass a removedSeparatorBuilder to removeItem and removeAllItems: #144899 From a user's perspective, I like solution 3 the most, because the API seems the cleanest and is familiar in regards to ListView.separated. Looking forward to hearing your opinion, or ideas on how to improve on these approaches. |
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.
Wow thank you so much for digging into this so thoroughly! Sorry it took me a while to review all of the options you presented, with sample code too, so grateful you included that. :)
I really like option 3 too, consistency across APIs is really wonderful when we can achieve it. Shall we go with 3 then?
This is a really fantastic contribution for a first PR, thank you again.
Sounds good! I will update this PR to use option 3 tomorrow. :) |
@Hixie @Piinks There is a limitation regarding Let me know if we should consider more options, or should just go with this solution for now. Looking forward to your reviews! :) |
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.
Thank you for the updates, and for your patience!
examples/api/lib/widgets/animated_list/animated_list_separated.0.dart
Outdated
Show resolved
Hide resolved
/// [MediaQuery]'s padding. To avoid this behavior, override with a | ||
/// zero [padding] property. |
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.
Should 'zero' here be [EdgeInsets.zero]
?
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, I copy pasted this from [AnimatedList]'s docstring :)
Maybe @HansMuller or @TahaTesser can give more insights?
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.
Hmm. We should probably know what these docs mean before we commit this.
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.
Depending on the use case one might want to remove only the padding for a specific side. So IMO "override with a zero [padding] property." is more fitting than "override with EdgeInsets.zero
[padding] property."
What do you think?
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.
SGTM! Thanks for verifying!
/// | ||
/// {@tool snippet} | ||
/// The following example demonstrates how to override the default top and | ||
/// bottom padding using [MediaQuery.removePadding]. |
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.
Is this another way, other than zero padding?
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.
see answer regarding 'zero'
ae398f4
to
be85aee
Compare
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.
Looks like it's just a few docs nits remaining here, very nearly ready to land! :)
return SizeTransition( | ||
sizeFactor: animation, | ||
child: ItemSeparator( | ||
animation: animation, | ||
item: null, | ||
) | ||
); |
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 indentation here is off, can you fix it?
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.
fixed :)
/// [MediaQuery]'s padding. To avoid this behavior, override with a | ||
/// zero [padding] property. |
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.
Hmm. We should probably know what these docs mean before we commit this.
62d9f7a
to
a040676
Compare
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.
…mBuilder docstring
Co-authored-by: Kate Lovett <katelovett@google.com>
Co-authored-by: Nate <nathan.wilson1232@gmail.com>
41226da
to
03d0fcc
Compare
auto label is removed for flutter/flutter/144899, due to - The status or check suite Linux build_tests_1_3 has failed. Please fix the issues identified (or deflake) before re-applying this label. |
A build check fails with
Is that related to the broken tree? Can I do anything to fix this? OutOfMemoryError to me looks unrelated to the changes. |
I believe that error was a flake—we just needed to re-run the test :) When that happens in the future, feel free to click the "Rebase branch" button, or you can wait for somebody with commit access to manually reboot the failing tests. |
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 p.trost93@gmail.com Feature: Add AnimatedList with separators (flutter/flutter#144899) 2024-06-05 yjbanov@google.com 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 engine-flutter-autoroll@skia.org Roll Flutter Engine from e88469090fed to 11a32d43e3f6 (2 revisions) (flutter/flutter#149699) 2024-06-05 gspencergoog@users.noreply.github.com Request focus if `SemanticsAction.focus` is sent to a focusable widget (flutter/flutter#142942) 2024-06-04 engine-flutter-autoroll@skia.org Roll Flutter Engine from 3dd40156afb6 to e88469090fed (2 revisions) (flutter/flutter#149695) 2024-06-04 katelovett@google.com TreeSliver & associated classes (flutter/flutter#147171) 2024-06-04 engine-flutter-autoroll@skia.org 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 47866232+chunhtai@users.noreply.github.com Prepares semantics_update_test for upcoming heading level changes (flutter/flutter#149671) 2024-06-04 34871572+gmackall@users.noreply.github.com Identify and re-throw our dependency checking errors in `flutter.groovy` (flutter/flutter#149609) 2024-06-04 hans.muller@gmail.com Scrollbar thumb drag gestures now produce one start and one end scroll notification (flutter/flutter#146654) 2024-06-04 15619084+vashworth@users.noreply.github.com Disable sandboxing for macOS apps and tests in CI (flutter/flutter#149618) 2024-06-04 engine-flutter-autoroll@skia.org Roll Flutter Engine from e211c43f3dc1 to fe00f023666c (3 revisions) (flutter/flutter#149680) 2024-06-04 gspencergoog@users.noreply.github.com Allow `find.byTooltip` to use a RegEx (flutter/flutter#149348) 2024-06-04 engine-flutter-autoroll@skia.org 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 dit@google.com,rmistry@google.com,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
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 p.trost93@gmail.com Feature: Add AnimatedList with separators (flutter/flutter#144899) 2024-06-05 yjbanov@google.com 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 engine-flutter-autoroll@skia.org Roll Flutter Engine from e88469090fed to 11a32d43e3f6 (2 revisions) (flutter/flutter#149699) 2024-06-05 gspencergoog@users.noreply.github.com Request focus if `SemanticsAction.focus` is sent to a focusable widget (flutter/flutter#142942) 2024-06-04 engine-flutter-autoroll@skia.org Roll Flutter Engine from 3dd40156afb6 to e88469090fed (2 revisions) (flutter/flutter#149695) 2024-06-04 katelovett@google.com TreeSliver & associated classes (flutter/flutter#147171) 2024-06-04 engine-flutter-autoroll@skia.org 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 47866232+chunhtai@users.noreply.github.com Prepares semantics_update_test for upcoming heading level changes (flutter/flutter#149671) 2024-06-04 34871572+gmackall@users.noreply.github.com Identify and re-throw our dependency checking errors in `flutter.groovy` (flutter/flutter#149609) 2024-06-04 hans.muller@gmail.com Scrollbar thumb drag gestures now produce one start and one end scroll notification (flutter/flutter#146654) 2024-06-04 15619084+vashworth@users.noreply.github.com Disable sandboxing for macOS apps and tests in CI (flutter/flutter#149618) 2024-06-04 engine-flutter-autoroll@skia.org Roll Flutter Engine from e211c43f3dc1 to fe00f023666c (3 revisions) (flutter/flutter#149680) 2024-06-04 gspencergoog@users.noreply.github.com Allow `find.byTooltip` to use a RegEx (flutter/flutter#149348) 2024-06-04 engine-flutter-autoroll@skia.org 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 dit@google.com,rmistry@google.com,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
This PR adds
AnimatedList.separated
. A widget like an AnimatedList with animated separators.animated_list_separated.0.dart
extendsanimated_list.0.dart
to work withAnimatedList.separated
Related issue: #48226
Pre-launch Checklist
///
).If you need help, consider asking for advice on the #hackers-new channel on Discord.