Open jacobg opened 8 years ago
Thanks @martingust. I guess if it's a non-default option, then it's up to the developer whether to accept any performance or scroll-quirkiness issues.
Ext JS (Sencha Touch) has an implementation for this in their List: http://docs.sencha.com/extjs/6.0/6.0.1-modern/#!/api/Ext.dataview.List Look for "variableHeights" in the source code.
I'm not totally familiar with their implementation, but I think they adjust the scroll height as user scrolls down the list. This issue will come up anyway for an infinite paging list.
Ideas for how to get dynamic height mentioned here: https://github.com/aurelia/ui-virtualization/issues/23#issuecomment-159638970. Thoughts?
I have tinkered with such things in the past so here are some options from my experiences.
The culprit is that you can't easily have pixel-based scrolling with virtualized lists of variable-height items because you would need to know the total height of the list, which means laying out the whole list, which is what you want to avoid.
Option 1: item-based scrolling. Rather than scrolling smoothly by pixel, do an item-by-item scroll. Drawback is that scrolling may not seem as smooth, especially if you animate it. But it does work well for large lists: did you notice Outlook does it for your mails list (at least if it's large)?
Possible mitigation (that Outlook does) is deferred scrolling: only updating the view when user releases the scrollbar. It hides the jerkiness somehow. Advantage: very fast scroll (no update!). Drawback: user can't see where he's at before releasing the mouse!
Possible mitigation: position tooltips when moving the scrollbar (like people name if the list is sorted by name, or e-mail date, or just item number, etc.).
Option 2: guess the total height and adjust. Make a guess for the total height based on the average height of items you've seen so far. When you materialized new items, update your average height and compute a new total height. Advantage: it works very nicely, especially with large list where you guess will be very close given the resolution of the scrollbar. Pixel-scrolling is nice and smooth. Drawback: Updating the total height can change the scrollbar height and position, which is disturbing if noticed by the user. Especially when dragging without deferred scrolling (see above).
Option 3: no scrollbar. Sometimes it is acceptable to only scroll by gestures (mouse wheel, panning by drag and drop). It's trivial to support variable-height items by keeping the index of the first visible item and a pixel offset into it.
Enhancement: a scroll position indicator can even easily be added to this setup (e.g. it appears when dragging or scrolling and then disappears) based upon item position rather than pixel position.
One more note: one needs to be very careful with how state is managed in virtualized list. Trying to work with pixels can easily overflows when computing total height of very large lists of moderately large items.
Also note that for very large lists all those smooth pixel-scrolling issues when dragging the scrollbar are basically non-issues because the scrollbar thumb will long be at its minimum size given the low resolution available. Those issues are mostly relevant when virtualizing medium to small-sized lists.
@jods4 I like option 2, for list with just slight different heights I think this is a very valuable ability and also with the option to turn off the scrollbar completely. Option 1 might be a good option for desktop, but maybe not very smooth on touch devices. Right now the plugin is undergoing some big refactoring to align it with the stock repeater, after that this should definitely be looked at. Thanks for valuable input.
+1 for an item based scrolling option. I'm using ui-virtualization in a chat channel where there is a big variation between item heights. Would also make it easier to scroll to a particular item, maybe?
@rquast, scroll to specific item is located here: https://github.com/aurelia/ui-virtualization/issues/80 In the mean time, I haven't tested this, so I have no idea about it's feasibility. But the variable item height might not be the end of the world bug for right now (don't get me wrong, I want this feature badly too ;) ). Right now we render a single item, measure it's height, and then figure out from that what the amount of items we can render at once are. If your first item is an "average" height, then you might be able to get away with variable heights. You would probably have more elements rendered at one time than would be optimized, but it still shouldn't destroy the DOM... Again, just some quick thoughts to maybe help you get at least running, no promise to whether or not it'd actually work.
In regards to the actual feature. What could be done to help figure out the heights is some math changing. If we calculate the height of each element as it is rendered and update our heights and other counts, that might be the approach to take. Ideally, we'd have a way to know which items we've rendered and counted towards our height count, so that if we scroll around, we're not triggering a recalculate twice on the same rendered element. This might be more of an issue when brought in with infinite scroll... @martingust, thoughts?
@AStoker rendering is really not an issue at all. Start with the first item visible and render as many items as you need to fill the viewport.
Where it gets very hairy is when it comes to managing the scrollbar. Basically, for a "traditional" scrollbar you would need to know the height of the complete viewport, which cannot be determinded in a variable-height, virtualized list. See my comments above for some options to work-around this.
@AStoker @jods4 I think it may help if someone forks the project and tries to implement a scroll by item, just as a test to see what it looks like and how it may work. May also help figure out what some of the problems will be when it comes to implementing it.
This is why the virtual repeater is still in "beta", still have time to tweak before it goes full V1 😄 I think a scroll by item approach would solve a number of the complexities that exist in virtual scrolling. I haven't had time to play around with that approach yet though. Any contributions from the community would be greatly appreciated. That's where the "open-source" part of the project comes in. Something doesn't work as well as you'd like, anybody is free to contribute and make it better. Basic constraints would be to keep the native scroll bar. Having a virtual scroll bar brings up other issues like styling and mobile/touch implementations.
Possibly another option 4: Provide a customizable call-back function for getting height of row fast, with parameter being item bound to the row. At least where I am using plugin the row height is going to be one of 1-4 sizes consistently based on the data i'm binding to the row. This would obviously not be automatic but at least would get it working
@jacobg This is something that we would like to support, not sure how it can be done just yet. The tricky part is to handle that without decreasing the performance too much. This plugin is under development and some big refactoring is planned so it will probably not happen before we beta release this. If you have any ideas please let me know.