~eliasnaur/gio#647: 
Scrolling in nested lists broken as of v0.8.0 (Android)

As of v0.8.0 scrolling appears to be broken when nesting lists (on Android). Attempting to scroll the list on android just does nothing. This is in comparison to old functionality in v0.7.0 wherein scrolling down on a nested list properly scrolled the list (e.g. if the cursor was within the nested list only). Note other platforms tested (such as Linux this bug does not effect).

Example: https://paste.sr.ht/~mil/df2af99291cd4bf2cda30d3184b3ca96220db5e5

Build the above example with gogio -target android .; and then compare the results swapping v0.7.0 and v0.8.0 in go.mod):


Looking into this further, I ran a git bisect and the breaking commit is: https://git.sr.ht/~eliasnaur/gio/commit/8fb6d3da2b015008ae9debb44241bef13b5c56fb

Prior to this commit nested list scrolling worked fine on Android and after, attempting scroll a nested list just nops.

Status
REPORTED
Submitter
~mil
Assigned to
No-one
Submitted
25 days ago
Updated
16 days ago
Labels
No labels applied.

~mil 25 days ago

Just to clarify as I can't edit the ticket - scrolling does work on the top-level list in either case..

But attempting to scroll within the nested listed is broken and has different / no functionality on v0.8.0

~whereswaldon 25 days ago

Thank you very much for the bisection! I think we need ~eliasnaur's input on this one.

~eliasnaur 23 days ago

Elias Naur referenced this ticket in commit efd31ad.

~eliasnaur 23 days ago

Thank you for the detailed report, and in particular the bisection. I've pushed a change that alleviates the problem a bit. Your example now scrolls, but not the inner list.

The diagnosis is that with the bisected change, both scrollable Lists receive the drag events, and both would execute a grab of the pointer. Before, the grabs would cancel each other out, but with the change the first grabber wins.

This is not a complete fix, because the outer List processes events before the nested List and thus wins the grab.

I'm not sure what the right fix is.

An option is to rework the List to process events last, but that complicates the List implementation and requires it to lay out children both before and and after scroll events.

Another option is to defer pointer grabs, and resolve multiple grabs by granting the top-most handler the grab, not just the first. This change seems right, and I started working on it. However, I ran into complexities during which I realized that not even top-most grabs will completely fix the issue: what is lacking is ability for the inner/top-most List to scroll until it reaches one of its extremes and then allow the outer List to continue scrolling. This is the behaviour of scroll (z-axis) events, and I'd like to have that for touch-based scrolling as well.

Scroll events are filtered by scroll distance, so perhaps something similar can be done here. Say, a pointer handler can declare its maximum drag distance in each direction, and then the Gio event machinery can route drag events to the handler that have remaining drag distance, prioritized by top-most-ness. That is, the inner List will be dragged until its extreme, and then the outer List and so on.

Since this is a bigger change, I won't be able to work on it right now, but I'd be happy to review any attempts at implementing it.

~mil 16 days ago*

I see - so I'm understanding this new behavior is inherent to the way event handling was refactored. Prior to the commit & in v0.7.0 scrolling in nested lists worked perfectly (scrolling the nested list when the cursor was there and the outer list when not focused on the nested list itself). But I suppose reverting the event handling logic refactor is infeasible / unrealistic

Scroll events are filtered by scroll distance, so perhaps something similar can be done here. Say, a pointer handler can declare its maximum drag distance in each direction, and then the Gio event machinery can route drag events to the handler that have remaining drag distance, prioritized by top-most-ness. That is, the inner List will be dragged until its extreme, and then the outer List and so on.

That sounds logical to me - however I'm not entirely too familiar with gio's underlying logic to be able to make the change myself.

I built & maintain an app based on gio which makes heavy use of nested lists as a UX pattern (unfortunately) so I'm currently blocked on app releases since gio v0.8.0 (and downgrading gio to v0.7.0 also isn't an option due to some go tooling version mismatch in the target builds I distribute on too).

~eliasnaur 16 days ago

I shall try to find some time to work on this, but it won't be before end of this month.

In the meantime, I encourage you look into adding DragX and DragY fields to pointer.Filter. They likely work similar to the existing ScrollX/ScrollY fields declared on line 68-69 in pointer.go. In fact, you may even get away with using the existing scroll limit values for drag limits for a prototype.

Register here or Log in to comment, or comment via email.