Skip to content
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

[New feature] Allowing the ListView slivers to have different extents while still having scrolling performance #131393

Merged
merged 18 commits into from
Sep 12, 2023

Conversation

xu-baolin
Copy link
Member

@xu-baolin xu-baolin commented Jul 27, 2023

Fixes #113431

Currently we only support specifying all slivers to have the same extent.
This patch introduces an itemExtentBuilder property for ListView, allowing the slivers to have different extents while still having scrolling performance, especially when the scroll position changes drastically(such as scrolling by the scrollbar or controller.jumpTo()).

@Piinks Hi, Any thoughts about this? :)

@flutter-dashboard
Copy link

It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie on the #hackers channel in Chat (don't just cc him here, he won't see it! He's on Discord!).

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.

@github-actions github-actions bot added framework flutter/packages/flutter repository. See also f: labels. f: scrolling Viewports, list views, slivers, etc. labels Jul 27, 2023
Copy link
Contributor

@Piinks Piinks left a comment

Choose a reason for hiding this comment

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

This looks very exciting! Thank you for putting this together!!
I am have been meaning to get to something similar, just have not had the opportunity yet. I thought this type of approach would resolve #52207

@@ -16,6 +16,9 @@ import 'viewport_offset.dart';
// CORE TYPES FOR SLIVERS
// The RenderSliver base class and its helper types.

/// Called to get the item extent by the index of item.
typedef ItemExtentGetter = double Function(int index);
Copy link
Contributor

Choose a reason for hiding this comment

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

What do you think of passing an index plus a little bit more information about the viewport?

My original thought for this was to see what folks thought of the TableSpanExtent API in the TableView (flutter/packages#4536) and maybe move that into the framework.
This section of the design document talks about it (links direct to that section): https://docs.google.com/document/d/15ecTZE1g3WeswLGFWrnEgMP6SyL6jDRdxOgPsczOcV0/edit?resourcekey=0-yNd_qFhiPjz6z2TgezWc0A#heading=h.a8uex5ucyiso

It defines multiple ways for developers to set an extent, based on the viewport, or the preceding scroll extent, or as the result of an operation, etc.

I figured if it worked well for folks (we did already test it in a usability study), we could use it here as well, making it a super class like ChildScrollExtent or some such - names are hard. 😆

Copy link
Member Author

Choose a reason for hiding this comment

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

What do you think of passing an index plus a little bit more information about the viewport?

What do you think of exposing the SliverConstraints directly or just some of the key properity of viewport?

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmmm, that's a good idea! It won't communicate the information about how much the SliverList has laid out already though, since the SliverConstraints relate to the whole sliver and not its contents. What parts of SliverConstraints would be relevant to the user when building an item of the list? Definitely the viewportExtent I think. Maybe we can wrap those parts up in an object with additional info like how much extent has been laid out.

Copy link
Member Author

Choose a reason for hiding this comment

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

I have wraped some layout relation properity into SliverLayoutDimensions and exposed it to the callback.

Will finish the test cases ASAP.

@github-actions github-actions bot added the f: material design flutter/packages/flutter/material repository. label Aug 4, 2023
@xu-baolin xu-baolin force-pushed the xbl230727 branch 2 times, most recently from 2c7c823 to 696873e Compare August 8, 2023 10:18
@xu-baolin xu-baolin requested a review from Piinks August 8, 2023 11:21
Copy link
Contributor

@Piinks Piinks left a comment

Choose a reason for hiding this comment

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

So excited about this. 😁 Thanks for the update!

/// Called to get the item extent by the index of item.
typedef ItemExtentGetter = double Function(int index, SliverLayoutDimensions dimensions);

/// Holds the relation dimensions of the [RenderSliver] during layout.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// Holds the relation dimensions of the [RenderSliver] during layout.
/// Relates the dimensions of the [RenderSliver] during layout.
///
/// Used by...

Can add a reference to the item extent callback from sliver list / list view?

@@ -46,6 +47,9 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
/// The main-axis extent of each item.
double get itemExtent;

/// The main-axis extent callback of each item.
ItemExtentGetter? get itemExtentCallback => null;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
ItemExtentGetter? get itemExtentCallback => null;
ItemExtentGetter? get itemExtentBuilder => null;

WDYT of this name?

@xu-baolin xu-baolin force-pushed the xbl230727 branch 3 times, most recently from 3431ac5 to 6b46dc6 Compare August 11, 2023 05:37
Copy link
Contributor

@Piinks Piinks left a comment

Choose a reason for hiding this comment

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

I think this is nearly there. Thank you very much for putting this together, and for your patience. I found the issue requesting this and added it to the description.

packages/flutter/lib/src/material/reorderable_list.dart Outdated Show resolved Hide resolved
}

@override
double get itemExtent => double.nan;
Copy link
Contributor

Choose a reason for hiding this comment

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

Could this be nullable? Or maybe we can add an assertion as the body of this getter that says this should not be used?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I have change it to nullable and add a assertion at the beginning of RenderSliverFixedExtentBoxAdaptor.performLayout()

    assert((itemExtent != null && itemExtentBuilder == null) ||
        (itemExtent == null && itemExtentBuilder != null));
    assert(itemExtentBuilder != null || (itemExtent!.isFinite && itemExtent! >= 0));

/// extent in the main axis.
/// * [SliverFillViewport], which sizes its children based on the
/// size of the viewport, regardless of what else is in the scroll view.
class SliverExplicitExtentList extends SliverMultiBoxAdaptorWidget {
Copy link
Contributor

Choose a reason for hiding this comment

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

In general, does this need to be it's own class? Would it be possible to use SliverFixedExtentList for both cases? I am curious for your thinking first, no need to change the code right now. As a developers, I wonder, what is the difference between Fixed and Explicit?

Copy link
Member Author

Choose a reason for hiding this comment

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

I have considered extending SliverFixedExtentList to support variable extent.
But I'm worried that this will break the developer's understanding of SliverFixedExtentList.
Maybe we need a better name to tell them the difference between the two.
It's really hard to name it, any suggestions? 😄

Copy link
Contributor

Choose a reason for hiding this comment

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

But I'm worried that this will break the developer's understanding of SliverFixedExtentList.

I agree with you on this. Sorry if my question led to some code changes we should revert now. Let's keep SliverFixedExtent as it is, and integrate itemExtentBuilder into a new sliver like you proposed. :)

It's really hard to name it, any suggestions?

Hmmmm I agree names are hard.
What if...

  • SliverFixedExtentList, uses itemExtent, one fixed extent for all children
  • SliverVariedExtentList, uses itemExtentBuilder, children have extents provided by the builder

Then we can have them refer to one another for developers to choose what they would prefer to use.

As I was thinking about it this weekend, I think having separate render objects is a good idea. Keeps the code clearer, easier to follow, and maintain

Copy link
Member Author

Choose a reason for hiding this comment

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

That's a great name : )

@@ -46,6 +47,9 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
/// The main-axis extent of each item.
double get itemExtent;

/// The main-axis extent builder of each item.
ItemExtentGetter? get itemExtentBuilder => null;
Copy link
Contributor

Choose a reason for hiding this comment

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

What if when null, this builder just returns itemExtent for every index by default? Maybe it could simplify the code below with if (itemExtentBuilder == null)?

Copy link
Member Author

@xu-baolin xu-baolin Aug 16, 2023

Choose a reason for hiding this comment

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

I have added some docs for this.

  /// The main-axis extent builder of each item.
  ///
  /// If this is non-null, the [itemExtent] must be null.
  /// If this is null, the [itemExtent] must be non-null.
  ItemExtentBuilder? get itemExtentBuilder => null;

@GeylanKalafMohe
Copy link

Hello please approve

Copy link
Contributor

@Piinks Piinks left a comment

Choose a reason for hiding this comment

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

LGTM! I am really excited for folks to have this, thank you so much for your work on this! 🎉

@Piinks Piinks added the autosubmit Merge PR when tree becomes green via auto submit App label Sep 12, 2023
@auto-submit auto-submit bot merged commit a9fac73 into flutter:master Sep 12, 2023
67 checks passed
@oddko
Copy link

oddko commented Sep 12, 2023

Thank you so much for your great work !

@xu-baolin
Copy link
Member Author

xu-baolin commented Sep 12, 2023 via email

engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Sep 12, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Sep 12, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Sep 12, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Sep 12, 2023
@Piinks
Copy link
Contributor

Piinks commented Sep 12, 2023

Hope you guys enjoyed your trip to Shanghai last week : )

Absolutely! Meeting each other was a highlight of the trip! 🎉

Oh, by the way, I have recently been trying to introduce a caching mechanism to ListView to reduce unnecessary layout operations to further optimize its scrolling performance. I hope to find a better solution.

This is really interesting, I would be happy to hear more if you are interested in pursuing it. I think in some cases caching could work, we could see what it looks like to give developers the option. Not sure. :)

@Piinks Piinks added the c: new feature Nothing broken; request for a new capability label Sep 12, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Sep 12, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Sep 12, 2023
auto-submit bot pushed a commit to flutter/packages that referenced this pull request Sep 12, 2023
flutter/flutter@219efce...4e7a07a

2023-09-12 katelovett@google.com Remove chip tooltip deprecations (flutter/flutter#134486)
2023-09-12 engine-flutter-autoroll@skia.org Roll Flutter Engine from 8a8ddaeecf8a to d4698c65aa8d (2 revisions) (flutter/flutter#134553)
2023-09-12 katelovett@google.com Remove deprecated TextSelectionOverlay.fadeDuration (flutter/flutter#134485)
2023-09-12 engine-flutter-autoroll@skia.org Roll Flutter Engine from 25be03186d82 to 8a8ddaeecf8a (1 revision) (flutter/flutter#134545)
2023-09-12 engine-flutter-autoroll@skia.org Roll Packages from ef0c65e to e04ba88 (5 revisions) (flutter/flutter#134546)
2023-09-12 47866232+chunhtai@users.noreply.github.com Revert "Adds a parent scope TraversalEdgeBehavior and fixes modal rou� (flutter/flutter#134550)
2023-09-12 fluttergithubbot@gmail.com Marks Windows_android channels_integration_test_win to be unflaky (flutter/flutter#133129)
2023-09-12 engine-flutter-autoroll@skia.org Roll Flutter Engine from 4091167e402d to 25be03186d82 (1 revision) (flutter/flutter#134536)
2023-09-12 engine-flutter-autoroll@skia.org Roll Flutter Engine from 54175da7ba90 to 4091167e402d (1 revision) (flutter/flutter#134532)
2023-09-12 engine-flutter-autoroll@skia.org Roll Flutter Engine from 85f3f02e5c37 to 54175da7ba90 (2 revisions) (flutter/flutter#134531)
2023-09-12 engine-flutter-autoroll@skia.org Roll Flutter Engine from 1369ab35aaa7 to 85f3f02e5c37 (1 revision) (flutter/flutter#134519)
2023-09-12 engine-flutter-autoroll@skia.org Roll Flutter Engine from 2f1efe5967f3 to 1369ab35aaa7 (1 revision) (flutter/flutter#134512)
2023-09-12 engine-flutter-autoroll@skia.org Roll Flutter Engine from 4d8265cbc133 to 2f1efe5967f3 (3 revisions) (flutter/flutter#134511)
2023-09-12 engine-flutter-autoroll@skia.org Roll Flutter Engine from ee7215553deb to 4d8265cbc133 (1 revision) (flutter/flutter#134506)
2023-09-12 engine-flutter-autoroll@skia.org Roll Flutter Engine from 6ddee4423d2c to ee7215553deb (2 revisions) (flutter/flutter#134505)
2023-09-12 engine-flutter-autoroll@skia.org Roll Flutter Engine from a98348946d61 to 6ddee4423d2c (1 revision) (flutter/flutter#134490)
2023-09-12 xubaolin@oppo.com [New feature] Allowing the `ListView` slivers to have different extents while still having scrolling performance (flutter/flutter#131393)
2023-09-12 engine-flutter-autoroll@skia.org Roll Flutter Engine from 8389ad914b21 to a98348946d61 (4 revisions) (flutter/flutter#134487)
2023-09-12 kouhei.seino@woven-planet.global ScaleGestureRecognizer: make pointerCount public (flutter/flutter#127310)
2023-09-11 chinmay@blend.to Fix DataTable example not being scrollable (flutter/flutter#131556)
2023-09-11 engine-flutter-autoroll@skia.org Roll Flutter Engine from 06696e768c1b to 8389ad914b21 (2 revisions) (flutter/flutter#134469)
2023-09-11 christopherfujino@gmail.com [flutter_tools] disallow -O0 for flutter build web (flutter/flutter#134185)
2023-09-11 sokolovskyi.konstantin@gmail.com Cover focus tests with leak tracking (flutter/flutter#134457)
2023-09-11 engine-flutter-autoroll@skia.org Roll Flutter Engine from 0774ddcda9b0 to 06696e768c1b (4 revisions) (flutter/flutter#134462)
2023-09-11 sokolovskyi.konstantin@gmail.com Fix memory leak in RenderAnimatedSize (flutter/flutter#133653)
2023-09-11 engine-flutter-autoroll@skia.org Roll Flutter Engine from e42fd367adcb to 0774ddcda9b0 (1 revision) (flutter/flutter#134447)
2023-09-11 engine-flutter-autoroll@skia.org Roll Flutter Engine from d593002b7159 to e42fd367adcb (1 revision) (flutter/flutter#134444)
2023-09-11 engine-flutter-autoroll@skia.org Roll Packages from aaae5ef to ef0c65e (6 revisions) (flutter/flutter#134445)
2023-09-11 engine-flutter-autoroll@skia.org Roll Flutter Engine from 2b5961cbc40d to d593002b7159 (3 revisions) (flutter/flutter#134439)
2023-09-11 polinach@google.com Mark leak: instances of OpacityLayer, created by _RenderChip, should be disposed. (flutter/flutter#134395)

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 camillesimon@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://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Nov 15, 2023
sfshaza2 pushed a commit to flutter/website that referenced this pull request May 17, 2024
Updates the long list cookbook to add `ListView.extentItemBuilder`,
which was added recently for lists with extends of different sizes:
flutter/flutter#131393

## Presubmit checklist

- [x] This PR doesn’t contain automatically generated corrections
(Grammarly or similar).
- [x] This PR follows the [Google Developer Documentation Style
Guidelines](https://developers.google.com/style) — for example, it
doesn’t use _i.e._ or _e.g._, and it avoids _I_ and _we_ (first person).
- [x] This PR uses [semantic line
breaks](https://github.com/dart-lang/site-shared/blob/main/doc/writing-for-dart-and-flutter-websites.md#semantic-line-breaks)
of 80 characters or fewer.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
autosubmit Merge PR when tree becomes green via auto submit App c: new feature Nothing broken; request for a new capability f: material design flutter/packages/flutter/material repository. 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.

[Feature/Optimization] Add an itemExtentPerIndex property to ListView.builder
4 participants