-
Notifications
You must be signed in to change notification settings - Fork 164
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
Clarification about variable height list items and efficiency? #275
Comments
Yes, it is perhaps not shouted loudly enough from the rooftop. 😊 From the
Yes, it will appear to work fine; the trouble is that your scrolling will be broken under some conditions when the calculations about the item heights become wrong. The viewport logic does indeed make your selected item visible, but the logic that the List uses to fake that scrolling viewport does really depend on item height calculations. You'll probably see issues in scrolling behavior when you reach the top or bottom of a list, or when paging up and down.
That's right. In the early days, lists rendered every item and then just cropped the result. That led to O(n) rendering for lists, regardless of the number of visible entries in the viewport. The trade-off I made to deal with that was:
So this is all done in service of not rendering items you absolutely can't see. You mentioned that the optimization seemingly isn't working for you, but even with the optimization you may still need to consider the cost of rendering your items and add render caching, for example. |
To follow up a bit more, though: if you really need the functionality you're going for, you may just need to implement your own mechanism for it rather than using |
Ah sorry, I missed that. Got it, the trade-off makes sense. I've thought about this problem a bit in the setting of virtual DOM rendering in a browser, and I wonder what you think of the following idea to generalize Given a list of items of length N, compute an integral image of the item heights. (I.e. a list of length N where index N equals the sum of all heights from 0 to N inclusive.) The integral image can be computed in The user of this list would need to provide a callback or something when gives the height of an individual item, but other than that it seems like the nice interface of
Hmm, this still doesn't make sense because there's a distinct performance difference between a small number of items (enough to fill the viewport) and 100s/1000s. I'll have to look into it further though. |
That could work so long as the item renderings themselves actually obeyed the heights that are given. That makes for a brittle interface since the invariant is very easy to violate; getting this right would be the application author's responsibility, since it would entail ensuring that the item rendering behavior is deterministic enough. I'm also concerned that this is a rabbit hole; someone has to specify heights, and then they're going to want to get access to rendering information to figure out what the heights should be (e.g. if the list viewport width necessitates a change in item height). That could create a data dependency that is impossible to resolve, since that information isn't available until after rendering has occurred in most cases. But you're right that the current interface could hide that detail for users who don't want to mess with it (and just default the height of all elements to the constant item height that is already required). |
If it would be possible for me to see your source, I'd be happy to take a look. |
That's true, even in my own case it would be kind of a drag to write that callback since I want the contents of my expanded list items to be able to wrap with As an alternative (I'm sure you've thought about this a lot, but hopefully you'll humor me here) -- what about rendering every list item once and then caching their heights in a hash table? For most re-renders I would expect the list elements to be highly cacheable. This would make it possible to generate the integral image efficiently on rerender and would be ideal from a user point of view because it would "just work" without requiring height specification.
That would be fine, it's a soon to be released open source project. Let me just make sure I'm not crazy/come up with a good demonstration and I'll post a separate issue. |
Yeah, this is exactly the kind of situation I was referring to.
This could work but it does raise some other issues. Rendering all items can be prohibitively expensive (think thousands of items) so this will introduce a noticeable stutter in responsiveness whenever the whole list of items needs to be re-rendered. Also, doing this requires the user to take on the responsibility of cache invalidation. It's hard to know when to invalidate the cache; invalidating at the right time requires that the application developer be aware of how a terminal resize or application state change affects the behavior of all of the combinators affecting the list dimensions. The cache also needs to be invalidated when the list contents change, but that's easier to get right. I think you're right that in practice list items are highly cacheable, though. That's why I recommended considering caching above, but I think doing it in the general case -- especially with minimal user involvement -- is likely to be very hard to get right. I appreciate you trying to think of ways to tackle this, and I'm happy to keep bouncing around ideas!
Okay, great! |
That's a price I would be happy to pay if everything else worked as expected and it only happened in predictable situations like a terminal resize. I suspect the other people who have asked about variable size items in the past would be too. But if this kind of stutter is unavoidable then maybe it's worth creating a separate module
Hmm, my thought was that the
I was thinking about what you said earlier about this. If this would be considered a brittle interface, then isn't the current interface in which the user specifies a single height for all rows equally brittle? On reflection, it seems like it's not really valid to use Thanks for being so responsive on issues btw! |
Yes, it would be impossible to provide an
You're right that the current interface is also brittle, in that you can fail to honor your item height pledge, and if you do, scrolling computations will be wrong and lead to occasional strangeness. The case where your items are too high is easy to rectify by (me) adding a |
I do want to follow up on one thing, though: I definitely think it would be awesome to have a list that supported variable item heights. I think it might be good to start from scratch on making it rather than trying to massage the current If you do end up messing around with a patch to support this, I'd be happy to collaborate on it. |
@thomasjm it looks like there isn't more we can do on this ticket right now, so I'm inclined to close it. Let me know if there's more we should discuss. |
Sounds good -- I'd still like to try coming up with a solution to this, but the issue doesn't need to stay open in the meantime. |
Okay, thanks! |
I've been trying to use the
List
widget to make an application with mostly uniform-height list items, but an occasional list item that is larger. The idea is that if you hit enter on the selected list item, it "expands" to become larger and show more information. While researching this I've noticed the following:Brick.Widgets.List
haddocks telling me not to do this :)listItemHeight
and that it makes calculations on this basis. Also, looking through historical issues like Size of widget in viewport #169, Question: scrolling view #97, inconsistent scroll position after listMoveTo #11, Support optimized list rendering #7, vBox unusably slow if you give it hundreds of items #264, and Question: Variable Height List Widget #226, it seems this library has evolved in the direction of forbidding (discouraging?) variable height list items for reasons including ease of calculation and performance. So I'm wondering if I'm looking for trouble by doing this.Vector
container.)Any clarity you could add about when/how/whether to use variable sized items would be greatly appreciated.
(Also, the side question that originally sent me down this rabbit hole: is it possible to somehow get the offset from the top of the list to a given item, in the presence of variable sized items? What I'd really like to do is add a command that "recenters" a list in the way the Emacs
recenter-top-bottom
command does -- with the ability to move the selected list item either to the center of the scrolled region, to the top, or to the bottom.)The text was updated successfully, but these errors were encountered: