Trapped in a scrollview

hi

My app has a scores page which has been getting longer as I add more exercises, so I decided to use a scrollView widget.

The scores page has a link back to the main menu with a listener attached to it. Unfortunately since adding the scrollview the link is broken. Here’s the menu link listener:

backToMenuFromScoresListener = function(event)    if ( event.phase == "began" ) then         display.getCurrentStage():setFocus(event.target)     event.target:setFillColor(.87,.3,.1,.9)    elseif  ( event.phase == "ended" ) then     display.getCurrentStage():setFocus(nil)   mainData.scrollView:removeSelf() mainData.scrollView = nil     showMenu() end end

The first part of the listener works because I can see the colour of the link change, but the score page never disappears and I never get back to the menu…

If I rewrite the listener like this, then it works, so for some reason it’s not ‘hearing’ the “ended” portion of the tap from within the scrollView widget. (is it bad to do it as below?)

backToMenuFromScoresListener = function(event) if ( event.phase == "began" ) then         display.getCurrentStage():setFocus(event.target)     event.target:setFillColor(.87,.3,.1,.9)     display.getCurrentStage():setFocus(nil)   mainData.scrollView:removeSelf() mainData.scrollView = nil     showMenu() end end

I would add some print statements to see what’s going on:

backToMenuFromScoresListener = function(event) local json = require("json") print( json.prettify( event ) ) if ( event.phase == "began" ) then display.getCurrentStage():setFocus(event.target) event.target:setFillColor(.87,.3,.1,.9) display.getCurrentStage():setFocus(nil) mainData.scrollView:removeSelf() mainData.scrollView = nil showMenu() end end

and see what event’s your getting.  Also, how are you adding listeners to your text?

Rob

OK I added those lines, plus I put the "  elseif  ( event.phase == “ended” ) then " back in. 

When I tap the “Menu” link, this is the console output. There’s a began phase but no ended phase:

{

                      “id”:"<type ‘userdata’ is not supported by JSON.>",

                      “name”:“touch”,

                      “phase”:“began”,

                      “target”:{

                        “x”:113.83999633789,

                        “y”:56,

                        “_proxy”:"<type ‘userdata’ is not supported by JSON.>",

                        “_functionListeners”:{

                          “touch”:["<type ‘function’ is not supported by JSON.>"]

                        },

                        “removeSelf”:"<type ‘function’ is not supported by JSON.>",

                        “_cachedRemoveSelf”:"<type ‘function’ is not supported by JSON.>",

                        “_class”:{

                          “removeEventListener”:"<type ‘function’ is not supported by JSON.>",

                          “addEventListener”:"<type ‘function’ is not supported by JSON.>",

                          “__index”:"<reference cycle>"

                        }

                      },

                      “time”:613244.618,

                      “x”:125.87256622314,

                      “xStart”:125.87256622314,

                      “y”:61.869567871094,

                      “yStart”:61.869567871094

                    }

Here’s the function that contains the scrollView:

showAllScores = function() local function scrollListener( event ) [a bunch of print statements] &nbsp; &nbsp; return true end -- function &nbsp; &nbsp; mainData.scrollView = widget.newScrollView( { &nbsp; &nbsp; top = 0, &nbsp; &nbsp; left = 0, &nbsp; &nbsp; width = display.contentWidth, &nbsp; &nbsp; height = display.contentHeight, &nbsp; &nbsp; horizontalScrollDisabled = true, &nbsp; &nbsp; hideScrollBar = false, &nbsp; &nbsp; listener = scrollListener, &nbsp; &nbsp;&nbsp; }) local menuButton = display.newText ("menu", [...] local menuButtonBG = display.newRect(...) menuButtonBG:toBack()

menuButtonBG:addEventListener("touch",backToMenuFromScoresListener) for i=1,n do ...[create a bunch of display.newtext objects to display scores, then insert them in scrollView:] mainData.scrollView:insert(arrayToHoldScores[i].questionType) mainData.scrollView:insert(arrayToHoldScores[i].questions\_answered) mainData.scrollView:insert(arrayToHoldScores[i].correct) mainData.scrollView:insert(arrayToHoldScores[i].average) end -- for loop -- insert other display objecct in scrollview, including the menuButtonBG which has the listener: ... mainData.scrollView:insert(... ... mainData.scrollView:insert(menuButtonBG) -- menuBUttonBG has the listener attached that is supposed to go back to the menu

 

just following up on this. I fixed it, but with an unresolved mystery (see below) What I did was I separated my top menu from the scrollview. The two tappable items (that have listeners attached) are now in a separate display group, not in the scrollview widget.

This mostly worked, but there was an odd behavior I noticed afterwards: my link back to the main menu has the word “menu” with a coloured newRect background. It’s the newRect that has the listener attached. Now at first I found I could tap the top of this rectangle and go back to the menu, but the bottom of the rectangle only registered the beginning phase of the tap, but not the end phase (I had json.prettify to get console output from the listener). I also found that occasionally the app would crash on my test device when I was in a different module and tapped on the menu link there. The error message said that scrollview could not be found, which means that the listener that was supposed to have been deleted along with its display group was still there and listening.

I later discovered that the top of the scrollview was overlapping the menu link background rectangle. I’m guessing this is why the listener was only ‘hearing’ the beginning phase of the tap when I tapped the lower, overlapping portion of the rectangle. Once I got rid of the overlap, the rectangle and its listener seem to be functioning OK.

I have to say I’m a little baffled by all this: I have a newRect object with a touch listener attached, and if I tap on a portion of this object that happens to be overlapping a scrollView, then only the beginning  phase is heard by the listener, not the ended phase, and the listener remains listening even though the object it’s listening to is properly disposed of.

I have to say I’m a little baffled by all this: I have a newRect object with a touch listener attached, and if I tap on a portion of this object that happens to be overlapping a scrollView, then only the beginning  phase is heard by the listener, not the ended phase, and the listener remains listening even though the object it’s listening to is properly disposed of.

The touch is leaking through the scroll view behind. This happens because you don’t return true in the button touch handler. 

Read section “Tap/Touch Propagation” @ https://docs.coronalabs.com/guide/events/touchMultitouch/index.html

Perfect, thanks.

If I rewrite the listener like this, then it works, so for some reason it’s not ‘hearing’ the “ended” portion of the tap from within the scrollView widget. (is it bad to do it as below?)

backToMenuFromScoresListener = function(event) if ( event.phase == "began" ) then &nbsp; &nbsp; &nbsp; &nbsp; display.getCurrentStage():setFocus(event.target) &nbsp; &nbsp; event.target:setFillColor(.87,.3,.1,.9) &nbsp; &nbsp; display.getCurrentStage():setFocus(nil) &nbsp; mainData.scrollView:removeSelf() mainData.scrollView = nil &nbsp; &nbsp; showMenu() end end

I would add some print statements to see what’s going on:

backToMenuFromScoresListener = function(event) local json = require("json") print( json.prettify( event ) ) if ( event.phase == "began" ) then display.getCurrentStage():setFocus(event.target) event.target:setFillColor(.87,.3,.1,.9) display.getCurrentStage():setFocus(nil) mainData.scrollView:removeSelf() mainData.scrollView = nil showMenu() end end

and see what event’s your getting.  Also, how are you adding listeners to your text?

Rob

OK I added those lines, plus I put the "  elseif  ( event.phase == “ended” ) then " back in. 

When I tap the “Menu” link, this is the console output. There’s a began phase but no ended phase:

{

                      “id”:"<type ‘userdata’ is not supported by JSON.>",

                      “name”:“touch”,

                      “phase”:“began”,

                      “target”:{

                        “x”:113.83999633789,

                        “y”:56,

                        “_proxy”:"<type ‘userdata’ is not supported by JSON.>",

                        “_functionListeners”:{

                          “touch”:["<type ‘function’ is not supported by JSON.>"]

                        },

                        “removeSelf”:"<type ‘function’ is not supported by JSON.>",

                        “_cachedRemoveSelf”:"<type ‘function’ is not supported by JSON.>",

                        “_class”:{

                          “removeEventListener”:"<type ‘function’ is not supported by JSON.>",

                          “addEventListener”:"<type ‘function’ is not supported by JSON.>",

                          “__index”:"<reference cycle>"

                        }

                      },

                      “time”:613244.618,

                      “x”:125.87256622314,

                      “xStart”:125.87256622314,

                      “y”:61.869567871094,

                      “yStart”:61.869567871094

                    }

Here’s the function that contains the scrollView:

showAllScores = function() local function scrollListener( event ) [a bunch of print statements] &nbsp; &nbsp; return true end -- function &nbsp; &nbsp; mainData.scrollView = widget.newScrollView( { &nbsp; &nbsp; top = 0, &nbsp; &nbsp; left = 0, &nbsp; &nbsp; width = display.contentWidth, &nbsp; &nbsp; height = display.contentHeight, &nbsp; &nbsp; horizontalScrollDisabled = true, &nbsp; &nbsp; hideScrollBar = false, &nbsp; &nbsp; listener = scrollListener, &nbsp; &nbsp;&nbsp; }) local menuButton = display.newText ("menu", [...] local menuButtonBG = display.newRect(...) menuButtonBG:toBack()

menuButtonBG:addEventListener("touch",backToMenuFromScoresListener) for i=1,n do ...[create a bunch of display.newtext objects to display scores, then insert them in scrollView:] mainData.scrollView:insert(arrayToHoldScores[i].questionType) mainData.scrollView:insert(arrayToHoldScores[i].questions\_answered) mainData.scrollView:insert(arrayToHoldScores[i].correct) mainData.scrollView:insert(arrayToHoldScores[i].average) end -- for loop -- insert other display objecct in scrollview, including the menuButtonBG which has the listener: ... mainData.scrollView:insert(... ... mainData.scrollView:insert(menuButtonBG) -- menuBUttonBG has the listener attached that is supposed to go back to the menu

 

just following up on this. I fixed it, but with an unresolved mystery (see below) What I did was I separated my top menu from the scrollview. The two tappable items (that have listeners attached) are now in a separate display group, not in the scrollview widget.

This mostly worked, but there was an odd behavior I noticed afterwards: my link back to the main menu has the word “menu” with a coloured newRect background. It’s the newRect that has the listener attached. Now at first I found I could tap the top of this rectangle and go back to the menu, but the bottom of the rectangle only registered the beginning phase of the tap, but not the end phase (I had json.prettify to get console output from the listener). I also found that occasionally the app would crash on my test device when I was in a different module and tapped on the menu link there. The error message said that scrollview could not be found, which means that the listener that was supposed to have been deleted along with its display group was still there and listening.

I later discovered that the top of the scrollview was overlapping the menu link background rectangle. I’m guessing this is why the listener was only ‘hearing’ the beginning phase of the tap when I tapped the lower, overlapping portion of the rectangle. Once I got rid of the overlap, the rectangle and its listener seem to be functioning OK.

I have to say I’m a little baffled by all this: I have a newRect object with a touch listener attached, and if I tap on a portion of this object that happens to be overlapping a scrollView, then only the beginning  phase is heard by the listener, not the ended phase, and the listener remains listening even though the object it’s listening to is properly disposed of.

I have to say I’m a little baffled by all this: I have a newRect object with a touch listener attached, and if I tap on a portion of this object that happens to be overlapping a scrollView, then only the beginning  phase is heard by the listener, not the ended phase, and the listener remains listening even though the object it’s listening to is properly disposed of.

The touch is leaking through the scroll view behind. This happens because you don’t return true in the button touch handler. 

Read section “Tap/Touch Propagation” @ https://docs.coronalabs.com/guide/events/touchMultitouch/index.html

Perfect, thanks.