Virtual Flow enhancements
John Hendrikx
john.hendrikx at gmail.com
Tue Sep 13 18:16:28 UTC 2022
I think it would be very good to add high level tests for those general
use cases -- I've always found the VirtualFlow code quite complicated,
but most of that comes from the need to allow different heights.
Not sure if this is relevant, but perhaps it is one of those "common
sense" cases: one thing I missed since the inception of these controls
is a way to position them in a such a way that they (pixel perfectly)
show a certain state, tracking a cell or position, to allow me to show
the control exactly the same as it was last time, or that the control
tracks the position of a cell that may still be in flux (due to
background loading of data).
For example, I scrolled my list so that the first Item is half visible
(at the top), and the fifth item is a quarter visible (at the bottom)
and I double click the 3rd item to go to a new screen (destroying the
original list view in the process), I find there is no way to recreate
the list view in the exact same state as it was before.
[ The part below turned out to be a bit of ramble... I could perhaps
turn it into a ticket if others agree -- I think it also shows that
there may not be one correct way to handle the scroll / positioning
behavior of a list view, and that more user control could be warranted ]:
Preferably, I'd be able to tell the view, show item X (the one I double
clicked) at the same vertical position as it was before. If the list
meanwhile changed and there are other items before/after it, then those
are allowed to be different, but the item I clicked should be in the
exact same position. The only exception is if there are insufficient
items before item X now, then it is acceptable to show X in a higher
position. The scrollTo function doesn't quite capture that (and has
been generally unreliable IIRC requiring `Platform.runLater` wrapping
for example).
Perhaps support something like an anchor position, which is updated
**only** when there is user interaction (selecting, scrolling, using
scroll keys). The only other way to change it would be programmatically.
The anchor would indicate the preferred cell or part of the view to keep
in an exact stable position and is never changed by the view itself
unless there was some interaction (ie. size changes of cells and the
view do not change the anchor, and neither do changes in the underlying
list of items). Not even a removal of the anchored index or item should
update the anchor -- instead the view should fall back to a secondary
anchor of its own choosing. If the index or item later is available
again, it will start using the primary anchor again.
The anchor should support I think three use cases:
- Anchoring an index
- Anchoring an item T
- Anchoring a scroll percentage
Anchoring an index would allow you to simply keep whatever item is at a
certain index at a stable position. This could be the first item or the
current last item, regardless of size changes or new items being
added/removed. Using an index of Integer.MAX_VALUE could be supported
here as an alternative to anchoring the bottom scroll position to the
bottom of the view.
Similarly, anchoring a specific item T would keep that item in a stable
position, even if the list is sorted, items around it are added or
removed or the item itself changes size.
Anchoring a scroll percentage allows you to keep the view at a fixed
position. Anchoring it at the bottom for example would be suitable for
lists where the latest added items should be kept in view at all times.
The anchor is changed by the view code when the user selects an item to
that specific item in that specific position (Item X should appear at
25% of the control height). The anchor is also changed when the user
uses the scroll bar, fixing it at percentage 0 or 100 if the bar was
moved all the way to the top or bottom, and on the top item otherwise
(this behavior may need to be selectable). Similar changes of the
anchor are allowed for navigation keys, up, down, pg up, pg down, home, end.
To show the 42nd item in the exact center of the view do (and keep it
there regardless of items appearing/disappearing/growing/shrinking):
setAnchoredIndex(42, 0.5, 0.5); // item 42's center is shown at
the view center
To show the 42nd item's top exactly at 25% of the view:
setAnchoredIndex(42.0, 0.0, 0.25); // item 42's top is shown at
25% of the views height
Item anchors:
setAnchoredItem(itemX, 0.5, 0.5); // itemX's center is shown at
the exact center
Scroll anchors:
setAnchoredPosition(1.0, 1.0); // keep bottom of list at all times
at bottom of view
Note that you could also ensure there is 50% empty space with an anchor
at the top or bottom, like this:
setAnchoredPosition(1.0, 0.5); // keep bottom of list at all times
at 50% of the view
For a list with images for example, which are often lazily loaded and
have various sizes, the anchor would allow a user to easily say which
item should be visible and where it is should appear relatively in the
view, even if the item is not yet fully loaded; ie. setting the anchor
with `setAnchoredItem(myLazyImageItem, 0.5, 0.5)` might initially
display a small place holder cell in the exact center of the view, but
once the image is loaded it might be much bigger and the view would jump
to allow this; with the anchor, the image would remain in the exact
center. Only if the image is higher than the view itself it would be
scrolled a bit to show its top.
--John
On 13/09/2022 11:02, Johan Vos wrote:
> Hi,
>
> OpenJFX 17 contains a fix for JDK-8089589 [1] ([ListView] ScrollBar
> content moves toward-backward during scrolling.) Before this fix, the
> scrollbar in the VirtualFlow backing List/Table/TreeTableView controls
> was treating every cell of equal height. That generated an awkward
> scrolling experience, especially when there are major differences in
> sizes in the backing list.
>
> The original fix introduced some new issues, and most of these are
> meanwhile fixed, and tests are added (thanks to e.g. Florian Kirmaier
> who created a good amount of tests).
>
> However, people have in the past been relying on undocumented behavior
> while creating apps and libraries, and that behavior is not guaranteed
> anymore with the fix for JDK-8089589 that went into OpenJFX 17.
> Most of these cases are related to
> (1) assuming that IndexedCell.updateItem() is only called when an item
> is (about to be) shown and
> (2) assuming that the value returned by the positionProperty of the
> scrollbar thumb is linearly related to the index of the item in the
> backinglist being shown.
>
> Both of these assumptions are invalid, but were (more or less)
> happening before JavaFX 17.
> I have seen a fair amount of creative implementations that somehow get
> and process information about the position of elements in the
> controls. Some of these relied on the false assumptions above, and are
> obviously no longer working.
> Instead of providing fixes per case, I think it would be good to
> capture the common use cases, and make it easier for developers to
> achieve what they want to achieve. I didn't yet encounter a use case
> that can not be implemented with the current approach (using public
> API's only), but granted, implementations often require too much
> boilerplate and wiring code.
>
> Crucial in this exercise are tests. There are a fair amount of tests
> for the list/table/treetableview controls, but only few of them are
> focused on external access and behavior.
> For all the fixes done so far in VirtualFlow, additional tests have
> been written which are now excellent regression tests. The last thing
> we want is that a fix for usecase A is not working anymore after a fix
> for usecase B.
>
> Hence, I'd like us to do 2 things:
> 1) for issues that are clearly bugs (*violating the JavaDoc*), please
> create JBS issues as usual (with failing test code).
> 2) for issues that are not violating the specs now, but are "common
> sense", please create a description and test scenario with expected
> versus actual outcome.
>
> I am not 100% sure what the best approach is to tackle issues that
> fall in the second category, but I suggest this: if you have a rather
> vague, abstract issue (e.g. "listview should always scroll to the
> bottom of the list IF it was at the bottom before and a new element is
> added") , it probably makes sense to first discuss it here. If on the
> other hand you have a very clear issue with a clear failing test, it
> can be a JBS issue as well -- but we need to keep in mind then that it
> might be in the category of "this fixes usescase A but blocks usecase B"
>
> Thanks,
>
> - Johan
>
> [1] https://bugs.openjdk.org/browse/JDK-8089589
More information about the openjfx-dev
mailing list