Buttons inside a scrollView - can't touch scrollView to stop inertial scrolling

In my game I have a few scrollViews that are filled with buttons. Per some documentation online, the suggested fix for the fact that you can’t scroll the scrollView if your touch input started on the button is:

 elseif event.phase == "moved" then levelSelectGroup:takeFocus( event ) end

This makes sense and works well. But if I scroll the list by flicking it and then try to stop it by tapping, the tap doesn’t stop the page from scrolling - I have to tap and move to stop. I’ve received feedback from users that they found my lists hard to use because of this.

It seems like the right thing would be (in pseudocode) to do something like:

if event.phase == "began" then if scrollView:isScrolling() then levelSelectGroup:takeFocus( event ) end end

But I have no way of testing whether the list is scrolling.

Any suggestions?

Hi @SecretAsianMan,

Are you not getting any response on the “event.phase == ‘began’” of the scrollView? Did you put a print() statement in there to check, not enclosed in any other conditional if-then check?

Brent

Thanks for the reply Brent.

I am definitely getting event.phase == “began” firing correctly, the problem is that there’s no way to actually test if the scrollView has inertial scrolling going. The scrollView:isScrolling() is something I made up, there’s nothing corresponding to this in the documentation.

Without knowing if it’s scrolling it means I’m intercepting the tap (and hold) 100% of the time and passing the event to the scrollView. This means that I can no longer press the buttons because event.phase == “ended” won’t fire if “began” passes focus to the scrollView :) 

e.g.:

 if event.phase == "began" then print("this fires just fine") myScrollView:takeFocus(event) -- We only want this line to fire if we're stopping scrolling, but there's no way to know if that's the case elseif event.phase == "ended" then print("this never fires because the began phase passed focus") elseif event.phase == "moved" then myScrollView:takeFocus(event) end

Hi @SecretAsianMan,

If you really want the scrolling to stop when you tap (“began” phase), regardless of whether it’s moving or not moving, how about just detecting the “began” phase, getting its Y position via “object:getContentPosition()”, then setting it to the same Y position via “object:scrollToPosition()” (with a time parameter of 0 for instantaneous effect). I haven’t tested that, but in theory that should make the scrolling stop instantly at the position it’s currently at, regardless of whether it’s moving.

Brent

Thanks Brent! This is a big step in the right direction, now I can stop the scroll as expected.

But now if I flick then tap to stop, it activates the button that I touched (when my intent was just to stop scrolling). Because I don’t know if the “began” phase input was being used to stop a scroll, I can’t decide whether or not to forward the event to the button. So it’s easy to accidentally trigger a button now.

I just want the scrollView to work like any scrolling list on iOS, Android, or Windows. For all of these if I use their native SDKs the list controls give me the behavior I’m looking for. Scroll events automatically get bubbled up to the nearest scroll container (with no code workaround), and touch input to stop an inertial scroll is taken by the scroll container and not its contents.

It seems like it’s not possible to achieve the expected scrolling behavior with scrollView :( 

Hi @SecretAsianMan,

Are you not getting any response on the “event.phase == ‘began’” of the scrollView? Did you put a print() statement in there to check, not enclosed in any other conditional if-then check?

Brent

Thanks for the reply Brent.

I am definitely getting event.phase == “began” firing correctly, the problem is that there’s no way to actually test if the scrollView has inertial scrolling going. The scrollView:isScrolling() is something I made up, there’s nothing corresponding to this in the documentation.

Without knowing if it’s scrolling it means I’m intercepting the tap (and hold) 100% of the time and passing the event to the scrollView. This means that I can no longer press the buttons because event.phase == “ended” won’t fire if “began” passes focus to the scrollView :) 

e.g.:

 if event.phase == "began" then print("this fires just fine") myScrollView:takeFocus(event) -- We only want this line to fire if we're stopping scrolling, but there's no way to know if that's the case elseif event.phase == "ended" then print("this never fires because the began phase passed focus") elseif event.phase == "moved" then myScrollView:takeFocus(event) end

Hi @SecretAsianMan,

If you really want the scrolling to stop when you tap (“began” phase), regardless of whether it’s moving or not moving, how about just detecting the “began” phase, getting its Y position via “object:getContentPosition()”, then setting it to the same Y position via “object:scrollToPosition()” (with a time parameter of 0 for instantaneous effect). I haven’t tested that, but in theory that should make the scrolling stop instantly at the position it’s currently at, regardless of whether it’s moving.

Brent

Thanks Brent! This is a big step in the right direction, now I can stop the scroll as expected.

But now if I flick then tap to stop, it activates the button that I touched (when my intent was just to stop scrolling). Because I don’t know if the “began” phase input was being used to stop a scroll, I can’t decide whether or not to forward the event to the button. So it’s easy to accidentally trigger a button now.

I just want the scrollView to work like any scrolling list on iOS, Android, or Windows. For all of these if I use their native SDKs the list controls give me the behavior I’m looking for. Scroll events automatically get bubbled up to the nearest scroll container (with no code workaround), and touch input to stop an inertial scroll is taken by the scroll container and not its contents.

It seems like it’s not possible to achieve the expected scrolling behavior with scrollView :(