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

Provide method and/or config to programmatically scroll to ListView index #12319

Open
ariejdl opened this Issue Sep 29, 2017 · 54 comments

Comments

@ariejdl

ariejdl commented Sep 29, 2017

The ListView is successful at displaying large lists, however in some circumstances, such as a reader application it is useful to be able to focus to a certain list item offset, the iOS UITableView has - (void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated and on Android the ListView has either setSelection(index); or smoothScrollToPosition(index). Please can you add this feature?

@ariejdl ariejdl changed the title from Provide method and or config to programmatically scroll to ListView index to Provide method and/or config to programmatically scroll to ListView index Sep 29, 2017

@ariejdl

This comment has been minimized.

Show comment
Hide comment
@ariejdl

ariejdl Oct 3, 2017

@Hixie is this a reasonable feature request?

ariejdl commented Oct 3, 2017

@Hixie is this a reasonable feature request?

@Hixie

This comment has been minimized.

Show comment
Hide comment
@Hixie

Hixie Oct 3, 2017

Contributor

It's certainly a reasonable request... how easy it is to implement is a different matter. :-)

For fixed-item-height list views it's easy to work around (just jump to the index * the height). For variable-height list views, it's really difficult in the current setup (because we don't know how far to scroll). It's the same thing that's blocking #10826.

Contributor

Hixie commented Oct 3, 2017

It's certainly a reasonable request... how easy it is to implement is a different matter. :-)

For fixed-item-height list views it's easy to work around (just jump to the index * the height). For variable-height list views, it's really difficult in the current setup (because we don't know how far to scroll). It's the same thing that's blocking #10826.

@ariejdl

This comment has been minimized.

Show comment
Hide comment
@ariejdl

ariejdl Oct 3, 2017

@Hixie please forgive my ignorance, but does it have to do with endScrollOffset < scrollOffset in performLayout in https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/rendering/sliver_list.dart#L213 ?

ariejdl commented Oct 3, 2017

@Hixie please forgive my ignorance, but does it have to do with endScrollOffset < scrollOffset in performLayout in https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/rendering/sliver_list.dart#L213 ?

@Hixie

This comment has been minimized.

Show comment
Hide comment
@Hixie

Hixie Oct 3, 2017

Contributor

That's part of the code that makes sure that widgets that aren't visible aren't laid out, yes. And that's the reason we don't know the offset for the widgets that aren't visible.

Contributor

Hixie commented Oct 3, 2017

That's part of the code that makes sure that widgets that aren't visible aren't laid out, yes. And that's the reason we don't know the offset for the widgets that aren't visible.

@sroddy

This comment has been minimized.

Show comment
Hide comment
@sroddy

sroddy Nov 25, 2017

Contributor

I have to add that I spent quite a few time in the past to figure out the fact that this feature is missing as I consider it being a critical requirement for a lot of common scenarios (chats, readers, contact lists just to name a few...) and for sure at least a couple of our apps.

While I understand the complexity of an animated version of this feature, I thought that a non-animated jumpToIndex(int index, {double position}) method shouldn't be that hard to implement, as it would require to just trigger a brand new render/layout of the visible area of the list starting from the element at the index we need to make visible (instead of index 0) and then walk up and down to fill the holes.

Contributor

sroddy commented Nov 25, 2017

I have to add that I spent quite a few time in the past to figure out the fact that this feature is missing as I consider it being a critical requirement for a lot of common scenarios (chats, readers, contact lists just to name a few...) and for sure at least a couple of our apps.

While I understand the complexity of an animated version of this feature, I thought that a non-animated jumpToIndex(int index, {double position}) method shouldn't be that hard to implement, as it would require to just trigger a brand new render/layout of the visible area of the list starting from the element at the index we need to make visible (instead of index 0) and then walk up and down to fill the holes.

@sroddy

This comment has been minimized.

Show comment
Hide comment
@sroddy

sroddy Nov 25, 2017

Contributor

another possible approach would be to be able to correctly estimate the height of the rows upfront and provide a correct offset to the jumpTo method. In one my specific use-cases the only variable part of the equation was to figure out how many rows a text label would have occupied when being rendered on the specific container. iOS has a method to achieve this (https://developer.apple.com/documentation/foundation/nsattributedstring/1529154-boundingrectwithsize), I''m wondering how to achieve the same goal with Flutter.

Contributor

sroddy commented Nov 25, 2017

another possible approach would be to be able to correctly estimate the height of the rows upfront and provide a correct offset to the jumpTo method. In one my specific use-cases the only variable part of the equation was to figure out how many rows a text label would have occupied when being rendered on the specific container. iOS has a method to achieve this (https://developer.apple.com/documentation/foundation/nsattributedstring/1529154-boundingrectwithsize), I''m wondering how to achieve the same goal with Flutter.

@GRouslan

This comment has been minimized.

Show comment
Hide comment
@GRouslan

GRouslan Nov 26, 2017

In case of smooth scrolling, if it is 1 element visible and 1001 is requested, no need to scroll through all 1000 elements.

GRouslan commented Nov 26, 2017

In case of smooth scrolling, if it is 1 element visible and 1001 is requested, no need to scroll through all 1000 elements.

@Hixie Hixie added this to the 4: Next milestone milestone Nov 28, 2017

@Hixie

This comment has been minimized.

Show comment
Hide comment
@Hixie

Hixie Nov 28, 2017

Contributor

This is definitely something we want to offer, we just haven't implemented it yet. The general case (animating to an item selected by index) is non-trivial, but we sort of need to know what our approach for that will be before we can design the API for the simpler cases as well.

Contributor

Hixie commented Nov 28, 2017

This is definitely something we want to offer, we just haven't implemented it yet. The general case (animating to an item selected by index) is non-trivial, but we sort of need to know what our approach for that will be before we can design the API for the simpler cases as well.

@DmitryIvanitskiy

This comment has been minimized.

Show comment
Hide comment
@DmitryIvanitskiy

DmitryIvanitskiy Mar 2, 2018

I made a small test app implementing ScrollToLine functionality, it should work also with mixed (different lineHeight) lists. The source: https://github.com/DmitryIvanitskiy/Animation/blob/master/main.dart
My approach is: ScrollToLine renders list twice:

  1. Render list truncated from start to target line (so ScrollController.position.maxScrollExtent is offset of the last line - save it).
  2. Render full list and animateTo offset we get on step 1.
    I encountered the following problem - ScrollController.position.maxScrollExtent didn't changes instantly after setState, but only after some (random, but short) time, solution made code extremely ugly...
    Is there a way to set a listener/callback directly to ScrollController.position.maxScrollExtent ?

DmitryIvanitskiy commented Mar 2, 2018

I made a small test app implementing ScrollToLine functionality, it should work also with mixed (different lineHeight) lists. The source: https://github.com/DmitryIvanitskiy/Animation/blob/master/main.dart
My approach is: ScrollToLine renders list twice:

  1. Render list truncated from start to target line (so ScrollController.position.maxScrollExtent is offset of the last line - save it).
  2. Render full list and animateTo offset we get on step 1.
    I encountered the following problem - ScrollController.position.maxScrollExtent didn't changes instantly after setState, but only after some (random, but short) time, solution made code extremely ugly...
    Is there a way to set a listener/callback directly to ScrollController.position.maxScrollExtent ?
@eseidelGoogle

This comment has been minimized.

Show comment
Hide comment
@eseidelGoogle
Contributor

eseidelGoogle commented Mar 29, 2018

@volgin

This comment has been minimized.

Show comment
Hide comment
@volgin

volgin Apr 11, 2018

In many use cases jumpTo(_index) is critical, while scrollTo(_index) is unnecessary or even undesirable.

If a user is in the middle of a long list, tapping to see the details and then coming back, scrolling all the way from the top to the desired position is a bad UX, whether it's manual or programmatic. I believe that jumpTo() is a major UX improvement in 100% of "coming back" use cases, while scrollTo is applicable only to a small subset of use cases.

volgin commented Apr 11, 2018

In many use cases jumpTo(_index) is critical, while scrollTo(_index) is unnecessary or even undesirable.

If a user is in the middle of a long list, tapping to see the details and then coming back, scrolling all the way from the top to the desired position is a bad UX, whether it's manual or programmatic. I believe that jumpTo() is a major UX improvement in 100% of "coming back" use cases, while scrollTo is applicable only to a small subset of use cases.

@AppleEducate

This comment has been minimized.

Show comment
Hide comment
@AppleEducate

AppleEducate Apr 23, 2018

I am currently running into this. Working with Lists from a REST API and up to 500-100 items in each list and every time more are added future builder gets called and it scrolls to the top. then you have to scroll all the way to the bottom.

AppleEducate commented Apr 23, 2018

I am currently running into this. Working with Lists from a REST API and up to 500-100 items in each list and every time more are added future builder gets called and it scrolls to the top. then you have to scroll all the way to the bottom.

@seenickcode

This comment has been minimized.

Show comment
Hide comment
@seenickcode

seenickcode May 17, 2018

This would be great for PageView as well.

seenickcode commented May 17, 2018

This would be great for PageView as well.

@marica27

This comment has been minimized.

Show comment
Hide comment
@marica27

marica27 May 20, 2018

I'm implementing gallery of photos and have a button "scroll to chosen date when photo was made". So scrollToPosition also important for me.

Calculating offset is not very accurate and on the long amount of data (2-4k photos) it's not right. And I could change the layout, so I would have to rewrite logic for calculating offset, especially to support changing orientation.

marica27 commented May 20, 2018

I'm implementing gallery of photos and have a button "scroll to chosen date when photo was made". So scrollToPosition also important for me.

Calculating offset is not very accurate and on the long amount of data (2-4k photos) it's not right. And I could change the layout, so I would have to rewrite logic for calculating offset, especially to support changing orientation.

@CyanBlob

This comment has been minimized.

Show comment
Hide comment
@CyanBlob

CyanBlob Jun 15, 2018

I would also love to have this feature. As it stands, I'm not really sure of a great way to implement a chat app where the message list starts scrolled to the latest message, especially since not all rows will have the same height

CyanBlob commented Jun 15, 2018

I would also love to have this feature. As it stands, I'm not really sure of a great way to implement a chat app where the message list starts scrolled to the latest message, especially since not all rows will have the same height

@zoechi

This comment has been minimized.

Show comment
Hide comment
@zoechi
Contributor

zoechi commented Jun 15, 2018

@zoechi

This comment has been minimized.

Show comment
Hide comment
@zoechi

zoechi Jun 15, 2018

Contributor

@marica27 does the scroll position really need to reflect the exact position over all photos?
You can query for a date in the database and just show the returned data with some extra length in front and after the shown images to make the ListView (or whatever you are using) scrollable.
You can show some short blurry scroll effect (up or down) without caring how far exactly the list would need to scroll. I don't think the users care if the scroll effect matches exactly 300 or 3000 images that might have scrolled by.

Contributor

zoechi commented Jun 15, 2018

@marica27 does the scroll position really need to reflect the exact position over all photos?
You can query for a date in the database and just show the returned data with some extra length in front and after the shown images to make the ListView (or whatever you are using) scrollable.
You can show some short blurry scroll effect (up or down) without caring how far exactly the list would need to scroll. I don't think the users care if the scroll effect matches exactly 300 or 3000 images that might have scrolled by.

@marica27

This comment has been minimized.

Show comment
Hide comment
@marica27

marica27 Jun 15, 2018

@zoechi Along with datePicker feature I have a draggable scrollbar showing date next to it. Have you seen Google Photos app or in Samsung Gallery App? So I want the same.
And now I'm realising that for this anyway I need to know the exact offset of all item. So scroll to position will not help me with it. And as i know offset for all items I can use it to scroll or jump to selected date.

marica27 commented Jun 15, 2018

@zoechi Along with datePicker feature I have a draggable scrollbar showing date next to it. Have you seen Google Photos app or in Samsung Gallery App? So I want the same.
And now I'm realising that for this anyway I need to know the exact offset of all item. So scroll to position will not help me with it. And as i know offset for all items I can use it to scroll or jump to selected date.

@zoechi

This comment has been minimized.

Show comment
Hide comment
@zoechi

zoechi Jun 15, 2018

Contributor

I need to know the exact offset of all item. So scroll to position will not help me with it.

I don't follow. If you know the offset, then you can just scroll there like _scrollController.animateTo(1500.0, duration: const Duration(milliseconds: 100), curve: Curves.easeOut);

Contributor

zoechi commented Jun 15, 2018

I need to know the exact offset of all item. So scroll to position will not help me with it.

I don't follow. If you know the offset, then you can just scroll there like _scrollController.animateTo(1500.0, duration: const Duration(milliseconds: 100), curve: Curves.easeOut);

@marica27

This comment has been minimized.

Show comment
Hide comment
@marica27

marica27 Jun 15, 2018

sorry for pure explanation. My list has 2 features. One is scroll to item with selected date and other is draggable scrollbar with label showing date for current position (as in google photos app).
When I wrote comment here first time I did not implement yet a draggable scrollbar so I did not know I need to know anyway offset for every item.
So, I'm going to calculate height of every item and it will resolve 2 my features.

marica27 commented Jun 15, 2018

sorry for pure explanation. My list has 2 features. One is scroll to item with selected date and other is draggable scrollbar with label showing date for current position (as in google photos app).
When I wrote comment here first time I did not implement yet a draggable scrollbar so I did not know I need to know anyway offset for every item.
So, I'm going to calculate height of every item and it will resolve 2 my features.

@CyanBlob

This comment has been minimized.

Show comment
Hide comment
@CyanBlob

CyanBlob Jun 15, 2018

@zoechi I had tried setting reverse: true, but that caused the newest messages to be on the top, which isn't what you want for a messaging window. As it turns out, I just wasn't thinking about the problem properly. The simple solution was to reverse the order in which I pull data from the server, along with reversing the render direction of the ListView

CyanBlob commented Jun 15, 2018

@zoechi I had tried setting reverse: true, but that caused the newest messages to be on the top, which isn't what you want for a messaging window. As it turns out, I just wasn't thinking about the problem properly. The simple solution was to reverse the order in which I pull data from the server, along with reversing the render direction of the ListView

@marcglasberg

This comment has been minimized.

Show comment
Hide comment
@marcglasberg

marcglasberg Jun 30, 2018

@Hixie @zoechi The core of this problem is that ListViews use a pixel offset, only. It will all be solved if you could use a pixelOffset+startIndex. At present, startIndex is implicitly always 0. So, if you want to start displaying item 1000, it has to calculate the size of all items from 0 to 999, just to know the pixel offset. Instead, to move to item 1000, some navigateToItem(1000) method could set pixelOffset to 0, and startIndex to 1000. Then, if you scroll to list to previous items you would have a negative pixelOffset. In other words, you just move the "origin" around.

marcglasberg commented Jun 30, 2018

@Hixie @zoechi The core of this problem is that ListViews use a pixel offset, only. It will all be solved if you could use a pixelOffset+startIndex. At present, startIndex is implicitly always 0. So, if you want to start displaying item 1000, it has to calculate the size of all items from 0 to 999, just to know the pixel offset. Instead, to move to item 1000, some navigateToItem(1000) method could set pixelOffset to 0, and startIndex to 1000. Then, if you scroll to list to previous items you would have a negative pixelOffset. In other words, you just move the "origin" around.

@marica27

This comment has been minimized.

Show comment
Hide comment
@marica27

marica27 Jul 1, 2018

I would be glad to have a special ListView with its special ScrollController which has method jumpTo(index) and maybe even animateTo(index)

I was trying myself to implement solution to achieve building ListView from startIndex. And I see that in a lot of places there is check on offset >= 0

@marcglasberg , what do you mean by pixelOffset in "pixelOffset+startIndex" ?

marica27 commented Jul 1, 2018

I would be glad to have a special ListView with its special ScrollController which has method jumpTo(index) and maybe even animateTo(index)

I was trying myself to implement solution to achieve building ListView from startIndex. And I see that in a lot of places there is check on offset >= 0

@marcglasberg , what do you mean by pixelOffset in "pixelOffset+startIndex" ?

@marcglasberg

This comment has been minimized.

Show comment
Hide comment
@marcglasberg

marcglasberg Jul 1, 2018

@marica27 Suppose you want to scroll to index 10000. You make pixelOffset = 0, and startIndex=10000. Then, when the builder asks for the item corresponding to some index, you simply return the item of startIndex+index.

At first, since we jumped to pixelOffset=0, the list will ask for the item at index = 0, right? But you will
return the item at startIndex+0=10000. If that item doesnt fill the screen, the list will ask for the next one, with index=1, and you will return the item at startIndex+1=10001. And so on.

So you see it will draw items starting at 10000. Now you just let the user scroll at will, and dont need to change the startIndex again, unless you need to do another jump. Say, that now you want to jump to item 5372. You simple make startIndex=5372 and pixelOffset=0.

Got it? The list doesnt need to check any items in-between, because it is just moving the ORIGIN. It's saying that pixelOffset=0 correspond to the item with the index you want to jump to. And then you can simply go to pixelOffset=0 to display that item.

The reason why you now need the ListView to scroll to negative values is that if pixelOffset=0 corresponds to index 5372, the user may want to scroll back to item 5371, which means a negative pixelOffset.

So, to start you need a unbounded ListView which can scroll to negative offsets. This link shows the technique to do just that: https://stackoverflow.com/questions/44468337/how-can-i-make-a-scrollable-wrapping-view-with-flutter

I don't think it would take you more than a day to implement this. Let me know if you need me to help you with that. I see that you are also in the Flutter Study Group, and I will say hi to you there if need to contact me.

marcglasberg commented Jul 1, 2018

@marica27 Suppose you want to scroll to index 10000. You make pixelOffset = 0, and startIndex=10000. Then, when the builder asks for the item corresponding to some index, you simply return the item of startIndex+index.

At first, since we jumped to pixelOffset=0, the list will ask for the item at index = 0, right? But you will
return the item at startIndex+0=10000. If that item doesnt fill the screen, the list will ask for the next one, with index=1, and you will return the item at startIndex+1=10001. And so on.

So you see it will draw items starting at 10000. Now you just let the user scroll at will, and dont need to change the startIndex again, unless you need to do another jump. Say, that now you want to jump to item 5372. You simple make startIndex=5372 and pixelOffset=0.

Got it? The list doesnt need to check any items in-between, because it is just moving the ORIGIN. It's saying that pixelOffset=0 correspond to the item with the index you want to jump to. And then you can simply go to pixelOffset=0 to display that item.

The reason why you now need the ListView to scroll to negative values is that if pixelOffset=0 corresponds to index 5372, the user may want to scroll back to item 5371, which means a negative pixelOffset.

So, to start you need a unbounded ListView which can scroll to negative offsets. This link shows the technique to do just that: https://stackoverflow.com/questions/44468337/how-can-i-make-a-scrollable-wrapping-view-with-flutter

I don't think it would take you more than a day to implement this. Let me know if you need me to help you with that. I see that you are also in the Flutter Study Group, and I will say hi to you there if need to contact me.

@rrousselGit

This comment has been minimized.

Show comment
Hide comment
@rrousselGit

rrousselGit Jul 5, 2018

While I can understand the need for a quick solution; I don't think we should take this approach.

I mean we're talking about forking ListView (and other scrollables too eventually) for just one method. That will be really confusing for users. Especially considering it'd require a custom API, ScrollController and would most likely be incompatible with CustomScrollView.

I think we should take a step back and see how we can change the current API to make it compatible with such jump.

In the meantime there's an easy workaround :

    SingleChildScrollView(
      child: Column(
        children: <Widget>[
          ...
        ],
      ),
    )

combined with Scrollable.ensureVisible(context).

rrousselGit commented Jul 5, 2018

While I can understand the need for a quick solution; I don't think we should take this approach.

I mean we're talking about forking ListView (and other scrollables too eventually) for just one method. That will be really confusing for users. Especially considering it'd require a custom API, ScrollController and would most likely be incompatible with CustomScrollView.

I think we should take a step back and see how we can change the current API to make it compatible with such jump.

In the meantime there's an easy workaround :

    SingleChildScrollView(
      child: Column(
        children: <Widget>[
          ...
        ],
      ),
    )

combined with Scrollable.ensureVisible(context).

@marcglasberg

This comment has been minimized.

Show comment
Hide comment
@marcglasberg

marcglasberg Jul 5, 2018

@rrousselGit We are obviously not talking about the same thing here, since Scrollable.ensureVisible(context) could not possibly solve the problem of having, say a database with 1 million items, and then jumping to the 100000th item without having to download all of them.

marcglasberg commented Jul 5, 2018

@rrousselGit We are obviously not talking about the same thing here, since Scrollable.ensureVisible(context) could not possibly solve the problem of having, say a database with 1 million items, and then jumping to the 100000th item without having to download all of them.

@ozexpert

This comment has been minimized.

Show comment
Hide comment
@ozexpert

ozexpert Jul 29, 2018

Any updates on supporting this feature? I need a solution and is a critical feature to me.

ozexpert commented Jul 29, 2018

Any updates on supporting this feature? I need a solution and is a critical feature to me.

@Hixie

This comment has been minimized.

Show comment
Hide comment
@Hixie

Hixie Jul 30, 2018

Contributor

There is a way to jump to a scroll offset.
If all your items are the same dimensions, then you can jump to the index * the height of your items to get to the specific item.

If your items are not all the same dimensions, then the problem is quite difficult and it's not at all clear how we should solve it. We need to know the scroll offset before we can begin layout, otherwise e.g. the scroll bar won't be able to show reasonable results. We can't find out the scroll offset without building and laying out everything between the current offset and the new one. We can't even know what direction we should be doing that in since the list could be infinite in both directions.

Contributor

Hixie commented Jul 30, 2018

There is a way to jump to a scroll offset.
If all your items are the same dimensions, then you can jump to the index * the height of your items to get to the specific item.

If your items are not all the same dimensions, then the problem is quite difficult and it's not at all clear how we should solve it. We need to know the scroll offset before we can begin layout, otherwise e.g. the scroll bar won't be able to show reasonable results. We can't find out the scroll offset without building and laying out everything between the current offset and the new one. We can't even know what direction we should be doing that in since the list could be infinite in both directions.

@ozexpert

This comment has been minimized.

Show comment
Hide comment
@ozexpert

ozexpert Jul 30, 2018

That is sad. Coming from Ionic framework, this feature is pretty much supported from v1. And yes, my list has dynamic height.

ozexpert commented Jul 30, 2018

That is sad. Coming from Ionic framework, this feature is pretty much supported from v1. And yes, my list has dynamic height.

@SteveAlexander

This comment has been minimized.

Show comment
Hide comment
@SteveAlexander

SteveAlexander Jul 31, 2018

I have scroll to item working on my flutter project, even though many items are variable height. The thing is, I can predict the height of each item from its data, without needing to render it. So although it's a little complicated, I can accurately calculate scroll positions.

But this would be so much easier if CustomScrollView were to work in a different way. I spent a day or so on this, but I'm afraid the relationship between ViewPort and ScrollPosition and various other collaborating objects got too complex for me in the time I had available. I'll try and describe what I was thinking below.

  1. For all of my needs so far, I don't need a scroll bar. I wonder whether supporting a scroll bar can be made optional in some way?

  2. In many cases we're talking about here (e.g. infinite scroll in both directions, large numbers of items of variable height or height that is only known on render) the scroll-bar dimensions are kind of ambiguous or guesses anyway. Like, if I scroll half way down a large number of variable-height items, and the bottom half of these aren't rendered yet, then what should a scroll-bar look like?

I wonder if a different kind of scroll view could be made to support this?

Starting from the idea of a ViewPort, and a particular "anchor" sliver being positioned somewhere within the viewport (e.g. top or centre), the ViewPort needs to render that sliver, and to be able to render the surrounding slivers to cover the viewport and whatever area above and below it are needed to enable smooth scrolling. Consider the scroll position as moving positively or negatively relative to the anchor sliver.

Then delegate the model behind the scrollbar to a specific object that knows how to make a scrollbar make sense for this particular case (it may be different each time), or allow to say "there is no scroll bar".

SteveAlexander commented Jul 31, 2018

I have scroll to item working on my flutter project, even though many items are variable height. The thing is, I can predict the height of each item from its data, without needing to render it. So although it's a little complicated, I can accurately calculate scroll positions.

But this would be so much easier if CustomScrollView were to work in a different way. I spent a day or so on this, but I'm afraid the relationship between ViewPort and ScrollPosition and various other collaborating objects got too complex for me in the time I had available. I'll try and describe what I was thinking below.

  1. For all of my needs so far, I don't need a scroll bar. I wonder whether supporting a scroll bar can be made optional in some way?

  2. In many cases we're talking about here (e.g. infinite scroll in both directions, large numbers of items of variable height or height that is only known on render) the scroll-bar dimensions are kind of ambiguous or guesses anyway. Like, if I scroll half way down a large number of variable-height items, and the bottom half of these aren't rendered yet, then what should a scroll-bar look like?

I wonder if a different kind of scroll view could be made to support this?

Starting from the idea of a ViewPort, and a particular "anchor" sliver being positioned somewhere within the viewport (e.g. top or centre), the ViewPort needs to render that sliver, and to be able to render the surrounding slivers to cover the viewport and whatever area above and below it are needed to enable smooth scrolling. Consider the scroll position as moving positively or negatively relative to the anchor sliver.

Then delegate the model behind the scrollbar to a specific object that knows how to make a scrollbar make sense for this particular case (it may be different each time), or allow to say "there is no scroll bar".

@rrousselGit

This comment has been minimized.

Show comment
Hide comment
@rrousselGit

rrousselGit Jul 31, 2018

The current scroll api is that complex not only because of scrollbars. Scrollbar is just one example.
A few others would be :

  • Parallax
  • Stricky Appbar/headers
  • scrollview background color change with scroll

The "anchor" solution proposed before would make these complicated.

rrousselGit commented Jul 31, 2018

The current scroll api is that complex not only because of scrollbars. Scrollbar is just one example.
A few others would be :

  • Parallax
  • Stricky Appbar/headers
  • scrollview background color change with scroll

The "anchor" solution proposed before would make these complicated.

@SteveAlexander

This comment has been minimized.

Show comment
Hide comment
@SteveAlexander

SteveAlexander Jul 31, 2018

Thanks @rrousselGit, it makes sense that these features rely on the current way of working.

I'm not proposing changing the current scrollview to work a different way. Rather, I'm asking what if there were a different (additional) kind of scroll view could be made to support viewport-oriented / anchored working, knowing that this additional kind of scrollview would not necessarily support the other features you mentioned.

SteveAlexander commented Jul 31, 2018

Thanks @rrousselGit, it makes sense that these features rely on the current way of working.

I'm not proposing changing the current scrollview to work a different way. Rather, I'm asking what if there were a different (additional) kind of scroll view could be made to support viewport-oriented / anchored working, knowing that this additional kind of scrollview would not necessarily support the other features you mentioned.

@marica27

This comment has been minimized.

Show comment
Hide comment
@marica27

marica27 Jul 31, 2018

I've dig in scrolling api twice. Everywhere I see that offset should be positive assert(offset >= 0). But it's still complicated for me to understand it good.
First I decide to make a RenderSliverList with initialIndex parameter and in performLayout to do what it usually does if ScrollController has initialOffset - do layout for items until offset is less initialOffset. So I do layout for items until index is less initialIndex. But cons of this solution is it has to layout all 1000 items if you need to jump to 1001. I call it IndexedListView.
Second solution actually was inspired by this SO and with help of @slightfoot. I call DividedListView. It divides list by selected index, builds stack with negative list and positive list. When user scrolls, positive scrollController changes offset of negative scrollController.
You can find code here
I notice a bug in it (negative list is seen behind when after jump), not in the video
devided_list_view

marica27 commented Jul 31, 2018

I've dig in scrolling api twice. Everywhere I see that offset should be positive assert(offset >= 0). But it's still complicated for me to understand it good.
First I decide to make a RenderSliverList with initialIndex parameter and in performLayout to do what it usually does if ScrollController has initialOffset - do layout for items until offset is less initialOffset. So I do layout for items until index is less initialIndex. But cons of this solution is it has to layout all 1000 items if you need to jump to 1001. I call it IndexedListView.
Second solution actually was inspired by this SO and with help of @slightfoot. I call DividedListView. It divides list by selected index, builds stack with negative list and positive list. When user scrolls, positive scrollController changes offset of negative scrollController.
You can find code here
I notice a bug in it (negative list is seen behind when after jump), not in the video
devided_list_view

@marica27

This comment has been minimized.

Show comment
Hide comment
@marica27

marica27 Jul 31, 2018

I've watched DartConf 2018 talk "It’s bigger on the inside: mind-bending scrolling in Flutter" of Eugenio Marletti @Takhion and my 3rd experiment would be create Viewport to support negative offset, and IndexedScrollController which can jumpTo(index)
I would not support other features that usual ListView has. In my app I need only jumpTo(index). I've tried calculate items height but it became too complicated and I gave it up.

It would be nice if somebody who knows scrolling api really good could make simple IndexedScrollView without support features which was mentioned above.

marica27 commented Jul 31, 2018

I've watched DartConf 2018 talk "It’s bigger on the inside: mind-bending scrolling in Flutter" of Eugenio Marletti @Takhion and my 3rd experiment would be create Viewport to support negative offset, and IndexedScrollController which can jumpTo(index)
I would not support other features that usual ListView has. In my app I need only jumpTo(index). I've tried calculate items height but it became too complicated and I gave it up.

It would be nice if somebody who knows scrolling api really good could make simple IndexedScrollView without support features which was mentioned above.

@sroddy

This comment has been minimized.

Show comment
Hide comment
@sroddy

sroddy Aug 6, 2018

Contributor

@Hixie

We need to know the scroll offset before we can begin layout, otherwise e.g. the scroll bar won't be able to show reasonable results. We can't find out the scroll offset without building and laying out everything between the current offset and the new one. We can't even know what direction we should be doing that in since the list could be infinite in both directions.

This is a very complex problem if you want to solve the issue with offsets, but definitely doable, even if not trivial, if you approach the problem considering a scrollToIndex API and you introduce a concept of estimated offset, which is something that is stable when the list is not scrolling, but can change and adapt while rendering scrolling animations. Talking high-level:

  1. you take note of the current visible indexes to determine the direction for the scrolling and rely on a provided estimate of the item size.
  2. you start offstage and lay out the desired widget for the given index at the given position in the viewport.
  3. you lay out enough indexes in the right direction in order to achieve the desired scrolling simulation.
  4. you go onstage and render a scroll view that starts from the furthest index. the offset here, for what regards the scrollbar etc, would be synthetic and computed from a given estimate of widgets' height (or a computed average of all the now rendered widgets) multiplied by the number of items in the list.
  5. you scrollTo the desired item offset
Contributor

sroddy commented Aug 6, 2018

@Hixie

We need to know the scroll offset before we can begin layout, otherwise e.g. the scroll bar won't be able to show reasonable results. We can't find out the scroll offset without building and laying out everything between the current offset and the new one. We can't even know what direction we should be doing that in since the list could be infinite in both directions.

This is a very complex problem if you want to solve the issue with offsets, but definitely doable, even if not trivial, if you approach the problem considering a scrollToIndex API and you introduce a concept of estimated offset, which is something that is stable when the list is not scrolling, but can change and adapt while rendering scrolling animations. Talking high-level:

  1. you take note of the current visible indexes to determine the direction for the scrolling and rely on a provided estimate of the item size.
  2. you start offstage and lay out the desired widget for the given index at the given position in the viewport.
  3. you lay out enough indexes in the right direction in order to achieve the desired scrolling simulation.
  4. you go onstage and render a scroll view that starts from the furthest index. the offset here, for what regards the scrollbar etc, would be synthetic and computed from a given estimate of widgets' height (or a computed average of all the now rendered widgets) multiplied by the number of items in the list.
  5. you scrollTo the desired item offset
@rrousselGit

This comment has been minimized.

Show comment
Hide comment
@rrousselGit

rrousselGit Aug 6, 2018

and rely on a provided estimate of the item size.

Interesting, but what is it used for?

rrousselGit commented Aug 6, 2018

and rely on a provided estimate of the item size.

Interesting, but what is it used for?

@sroddy

This comment has been minimized.

Show comment
Hide comment
@sroddy

sroddy Aug 7, 2018

Contributor

The idea is that the scrollview will consider that to be the size of any non rendered items (and use it e.g. for the offset, the scroll bar and the scroll physics).

It's the same approach adopted by Apple with their UICollectionView:
https://developer.apple.com/documentation/uikit/uicollectionviewflowlayout/1617709-estimateditemsize

Contributor

sroddy commented Aug 7, 2018

The idea is that the scrollview will consider that to be the size of any non rendered items (and use it e.g. for the offset, the scroll bar and the scroll physics).

It's the same approach adopted by Apple with their UICollectionView:
https://developer.apple.com/documentation/uikit/uicollectionviewflowlayout/1617709-estimateditemsize

@rrousselGit

This comment has been minimized.

Show comment
Hide comment
@rrousselGit

rrousselGit Aug 7, 2018

But how does that help solving the scroll problem? As you've said for jumps we'd start layout from the destination

rrousselGit commented Aug 7, 2018

But how does that help solving the scroll problem? As you've said for jumps we'd start layout from the destination

@debuggerx01

This comment has been minimized.

Show comment
Hide comment
@debuggerx01

debuggerx01 Aug 10, 2018

Contributor

I've writen a simple demo to show how I sovle this problem by using my widget named RectGetter:
demo

source code: JumpToIndexDemo

Contributor

debuggerx01 commented Aug 10, 2018

I've writen a simple demo to show how I sovle this problem by using my widget named RectGetter:
demo

source code: JumpToIndexDemo

@marcglasberg

This comment has been minimized.

Show comment
Hide comment
@marcglasberg

marcglasberg Aug 14, 2018

I have just published this:

https://pub.dartlang.org/packages/indexed_list_view

Similar to a ListView, but lets you programmatically jump to any item, by index. Items may have different sizes, it doesn't matter, the jump is always cheap and it doesn't need to build all widgets between the old and new positions. You can jump millions of items, instantly. Please run the example in the Example tab.

Currently, the list is always infinite, both to positive and negative indexes. In other words, it can be scrolled indefinitely both to the top and to the bottom. This is useful for some use cases, but it's a serious limitation for others. I don't understand the scrolling API well enough to allow passing lower and upper bounds as to make the list finite, so I would very much appreciate if someone could help me with that.

Having created that package, it's my opinion that solving #20608 would make it trivial to programmatically scroll to ListView index in both small and big lists.

marcglasberg commented Aug 14, 2018

I have just published this:

https://pub.dartlang.org/packages/indexed_list_view

Similar to a ListView, but lets you programmatically jump to any item, by index. Items may have different sizes, it doesn't matter, the jump is always cheap and it doesn't need to build all widgets between the old and new positions. You can jump millions of items, instantly. Please run the example in the Example tab.

Currently, the list is always infinite, both to positive and negative indexes. In other words, it can be scrolled indefinitely both to the top and to the bottom. This is useful for some use cases, but it's a serious limitation for others. I don't understand the scrolling API well enough to allow passing lower and upper bounds as to make the list finite, so I would very much appreciate if someone could help me with that.

Having created that package, it's my opinion that solving #20608 would make it trivial to programmatically scroll to ListView index in both small and big lists.

@debasmitasarkar

This comment has been minimized.

Show comment
Hide comment
@debasmitasarkar

debasmitasarkar Aug 27, 2018

@Hixie I am building an chat app..I am getting chat messages from Firebase database..Whch can be of dynamic number,using ListView.builder for messages to display.How can I autoscroll to the end of my list and on adding of message I need to autoscroll again..How can I implement this?Is there any easy way?

debasmitasarkar commented Aug 27, 2018

@Hixie I am building an chat app..I am getting chat messages from Firebase database..Whch can be of dynamic number,using ListView.builder for messages to display.How can I autoscroll to the end of my list and on adding of message I need to autoscroll again..How can I implement this?Is there any easy way?

@AppleEducate

This comment has been minimized.

Show comment
Hide comment
@AppleEducate

AppleEducate Aug 27, 2018

AppleEducate commented Aug 27, 2018

@debasmitasarkar

This comment has been minimized.

Show comment
Hide comment
@debasmitasarkar

debasmitasarkar Aug 28, 2018

@AppleEducate it helps when I am sending a message.But when I am getting all the messages for the first time , I mean opening Chat app and getting previous messages, I need something to autoscroll at the end of the current listview.

debasmitasarkar commented Aug 28, 2018

@AppleEducate it helps when I am sending a message.But when I am getting all the messages for the first time , I mean opening Chat app and getting previous messages, I need something to autoscroll at the end of the current listview.

@zoechi

This comment has been minimized.

Show comment
Hide comment
@zoechi

zoechi Aug 28, 2018

Contributor

@debasmitasarkar you might want reverse: true. With this you get that behavior automatically.

Contributor

zoechi commented Aug 28, 2018

@debasmitasarkar you might want reverse: true. With this you get that behavior automatically.

@debasmitasarkar

This comment has been minimized.

Show comment
Hide comment
@debasmitasarkar

debasmitasarkar Aug 28, 2018

@zoechi Yes I can do that..But my chat messages are sorted in a timely manner.So it would reverse the logic and show old data at the end and newest at the top

debasmitasarkar commented Aug 28, 2018

@zoechi Yes I can do that..But my chat messages are sorted in a timely manner.So it would reverse the logic and show old data at the end and newest at the top

@zoechi

This comment has been minimized.

Show comment
Hide comment
@zoechi

zoechi Aug 28, 2018

Contributor

Sorting the data in reverse order shouldn't cause any difficulty.
Updating the scroll position will be much less reliable.

Contributor

zoechi commented Aug 28, 2018

Sorting the data in reverse order shouldn't cause any difficulty.
Updating the scroll position will be much less reliable.

@debasmitasarkar

This comment has been minimized.

Show comment
Hide comment
@debasmitasarkar

debasmitasarkar Aug 28, 2018

@zoechi Thanks Friend!! I actually solved the issue with your tips 👍

debasmitasarkar commented Aug 28, 2018

@zoechi Thanks Friend!! I actually solved the issue with your tips 👍

@ozexpert

This comment has been minimized.

Show comment
Hide comment
@ozexpert

ozexpert Oct 23, 2018

When would we have a feature like scrollToIndex()? Any estimates on when this would be fixed?

ozexpert commented Oct 23, 2018

When would we have a feature like scrollToIndex()? Any estimates on when this would be fixed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment