Hi,
Using a TableListBox on iOS, there is some fight between the viewport and the row drag and drop operation: both scrolling and dragging are happening simultaneously.

Thanks for your help.
Hi,
Using a TableListBox on iOS, there is some fight between the viewport and the row drag and drop operation: both scrolling and dragging are happening simultaneously.

Thanks for your help.
Kindly asking for an update about this. It’s actually blocking a project. I think the drag and drop operation should only be started from an item that has already been tapped and is selected, and should not scroll the viewport in that case. Thanks for your feedback!
Any hope for this issue to be fixed soon, please?
Hello @anthony-nicholls, would you be able to have a look at this issue, please?
Thanks in advance.
Hi @mathieudemange thanks for reaching out. Unfortunately I probably can’t look at this today, I’ll keep you posted as to when I might be able to take a closer look. I can however confirm that I’ve reproduced this issue with the Demo runner.
No problem. Thanks for taking a look! Have a nice day.
Perhaps this is not simply a “bug”. I’m afraid that getting viewports to work properly with mobile devices would require updating many GUI objects and it is not quite clear how this should be done.
First off, in the case above, what should be the correct behaviour? There are several possibilities, for example:
The first option would work fine in many cases. But what if an action is taken when selecting an item, for example if the listBox is used as a menu? Then this would not work well. In that case the second option would be better, similar to how the reordering of items in a menu is commonly done. And in a context where the only action is to drag items out of a list, the third option would work best, as less clicking would be necessary.
So the actual implementation would need to take the context into consideration.
But the main problem stems from how JUCE objects react to mouse events generally. They normally react to gestures before it would be possible for a viewport to recognize the gesture as being a swipe or a drag.
In the example above, items are selected already when a mouse-down gesture occurs. That would need to be addressed. For example, items could instead be selected only after a mouse-up event and only if a click gesture took place.
The same applies to buttons. They don’t work nicely when placed in a viewport which can be dragged, because users expect to be able to drag or swipe a viewport even if initiating the gesture on a button.
Sliders are more tricky. For example, you might want horizontal sliders on a vertical viewport to “consume” horizontal drags immediately but to forward vertical drags to the viewport. Or you might prefer the sliders to only be draggable after clicking and holding them for some time, etc.
So, for viewports to work properly on touch devices, many GUI objects would need to be modified. They would need to check if they are in a draggable viewport and react to gestures accordingly: If a swipe or drag-to-scroll gesture is taking place, they should forward the gesture to the viewport and ignore the gesture, but if another type of gesture is taking place, they should consume it and block the viewport from being affected by the gesture (so that the viewport doesn’t move unintentionally). Additionally, there should be options to determine which gestures should be consumed, so it is possible to adapt to different use cases.
Improving viewports is not trivial but it would make developing for mobile platforms so much better. Right now, getting GUI elements to work properly can take A LOT of extra work, which is unnecessary on other frameworks.
I completely agree.
I think that iOS (I never used JUCE on Android and will probably never need to) is not precisely an equally “supported” platform as desktop platforms. I’m grateful for what it already is, but I think JUCE for iOS lacks real support for a multitouch device (e.g., gestures). And like you said, rethinking and updating the code for all the GUI elements is a lot of work. That would be a good topic for a significant update.
In the meantime, I would be very grateful if this one is resolved so I can continue moving forward and release our new app.
cant you check while dragging if the mouse is outside the list borders?
then you should be able to override the scrolling behaviour as soon as this happens.
On dragstart the current scrollpos should be noted, and when the mouse goes out of the box while dragging, the scroll should be reset.to that position
So you’d override some of the viewport events
I think this would still look glitchy that way. If you look at the GitHub issue I filed, I give some details about this.
I know this is not the same issue but it is kind of related: (dragging a viewport inside a viewport when scrollOnDrag is enabled):
Yes, this improvement should work equally well with mouse and touch devices.
I vaguely tried to do some step-by-step debugging to see how things worked in my case but I can’t remember having seen the doesMouseEventComponentBlockViewportDrag (...) method being called. Would it also be called when a TableListBox item is dragged?
You may be right, I assumed the ListBox was using scrollOnDragMode on iOS for its Viewport but I don’t see it in juce_ListBox.cpp , so maybe it works differently…
Finally took some time to investigate this issue. It comes down to disambiguating whether a drag gesture is meant for a list item (which should start a drag’n’drop operation) or the internal viewport (which should cause the viewport to scroll).
While ListBox and Viewport provide some input behaviour customisations, I think the touch interface of tactile devices is simply not suited for such flexibility and that some imposed settings are mandatory for the component to work as expected on touch devices.
In my case, for the TableListBox component to work with draggable items on iOS, here’s what’s involved:
setRowSelectedOnMouseDown (false) on the TableListBox component: otherwise, there’s no way to predict the intent behind a drag gesture.juce_ListBox.cpp, alter mouseDrag() {...} so the row that will be dragged can only be the one already selected.mouseUp(), re-enable viewport scrolling.I ended up with this hack:
void mouseUp (const MouseEvent& e) override
{
if (asBase().isEnabled() && selectRowOnMouseUp && ! (isDragging || isDraggingToScroll))
asBase().performSelection (e, true);
// *** Re-enable viewport scrolling. ***
if (auto* vp = getOwner().getViewport())
vp->setScrollOnDragMode (Viewport::ScrollOnDragMode::nonHover);
}
void mouseDrag (const MouseEvent& e) override
{
if (auto* m = getModel (getOwner()))
{
if (asBase().isEnabled() && e.mouseWasDraggedSinceMouseDown() && ! isDragging)
{
SparseSet<int> rowsToDrag;
if (getOwner().getRowSelectedOnMouseDown() || getOwner().isRowSelected (row))
rowsToDrag = getOwner().getSelectedRows();
// *** Do not accept any other rows than the currently selected one ***
/*
else
rowsToDrag.addRange (Range<int>::withStartAndLength (row, 1));
*/
if (! rowsToDrag.isEmpty())
{
auto dragDescription = m->getDragSourceDescription (rowsToDrag);
if (! (dragDescription.isVoid() || (dragDescription.isString() && dragDescription.toString().isEmpty())))
{
isDragging = true;
getOwner().startDragAndDrop (e, rowsToDrag, dragDescription, m->mayDragToExternalWindows());
// *** Prevent scroll in viewport ***
if (auto* vp = getOwner().getViewport())
vp->setScrollOnDragMode (Viewport::ScrollOnDragMode::never);
}
}
}
}
if (! isDraggingToScroll)
if (auto* vp = getOwner().getViewport())
isDraggingToScroll = vp->isCurrentlyScrollingOnDrag();
}
Then I get the expected behaviour.

Of course this is just a hack. I used the simplest ways to do things, like preventing the viewport to scroll: I’m not even sure that’s a good way to do it, even if it works, but I should’ve at least restored the previous state instead of enforcing ScrollOnDragMode::nonHover, etc.
Thanks for your feedback, hope this can be fixed soon.
Cheers.
Would it be possible to get some feedback from the team about this issue? Please ![]()