tableView intercepting button touch events

I am trying to implement a list of things shown using tableview with a plus button at the bottom to add a new item.  Something every app has these days.  But my touch events for my plus button keep getting overwritten by tableView events.  I get the first began for the button but nothing else.  I am looking for the release before I move to the add item page.  My button touch listener tries to setfocus but that doesn’t seem to help.  I put the following in my touch listener.  

if event.id then display.getCurrentStage():setFocus(event.target, event.id) end t.isFocus = true

That doesn’t seem to do it.  Since I get the first began for the button I guess I could disable the tableView somehow but that would involve my button class knowing something about what else is on the screen.  If I can avoid that it would make the code much cleaner.  

Also, I have a gameGroup and a FrontGroup in my sceneGroup.  the button is in the FrontGroup while the tableView should be behind it in the GameGroup.  But that doesn’t seem to help either. 

Any suggestions? 

L

Are you returning true after handing the touch event?

Rob

I wasn’t, so I changed it to this:  Does it look right?  I get the first “began” and nothing else.  

function M:touch\_listener( event ) local event = event local t = event.target local self = t.antecedent -- local sfx = GlblData.soundobject -- sound effects print ("button touch listener", event.phase , self , event.id ) if self then -- this listener was being called after the listener was removed and self:destroy was called. So things were failing. if self.buttonGroup.whichimage ~= "inactive" then if event.phase == "began" then self:begin\_rollover() if event.id then display.getCurrentStage():setFocus(event.target, event.id) end t.isFocus = true local uiEvent = {name = "onUIevent", phase = "pressed", buttonName = self.buttonName or "none" , target = t } Runtime:dispatchEvent(uiEvent) elseif ( event.phase == "moved" ) then self:begin\_rollover() self:rollovertimebump() -- bump out time to stay in rollover mode. elseif ( event.phase == "ended" or event.phase == "cancelled" ) then self:begin\_main() if event.id then display.getCurrentStage():setFocus(nil, event.id) end t.isFocus = false local uiEvent = {name = "onUIevent", phase = "released", buttonName = self.buttonName or "none" , target = t } print ("release event dispatched ", event.phase ) Runtime:dispatchEvent(uiEvent) end -- "ended" end end return true end

what happens in the various “rollover” code?  are you potentially swapping images?  any chance you’re setting focus on the wrong (hidden) one?

I have a displayGroup for 4 button images. (main, clicked, rollover, inactive ) I am swapping the images around depending on which one I want in front.  The touch listener is only on the DG.  

function M:addlistener( ) self.buttonGroup.touch = self.touch\_listener self.buttonGroup:addEventListener( "touch" , self.buttonGroup ) return end 

This is the main part of the rollover code.  

 self.image\_rollover.isVisible = true self.image\_inactive.isVisible = false self.image\_clicked.isVisible = false self.image.isVisible = false self.buttonGroup:insert(self.image\_rollover) -- put image on top

then i’d look around for consistent use of “self” and/or “buttonGroup”, for example:

 if self.buttonGroup.whichimage ~= "inactive" then 

seems suspect.  inside the listener, where M.touch_listener was assigned to buttonGroup.touch, “self” will refer to the same thing as event.target (ie the button group).  that code looks like you’re using “self” to mean “M”, but it won’t be (at least, not when called as the buttonGroup’s listener)  is that what “t.antecedant” is supposed to be resolving?  (it’s a bit difficult to follow given just snippets)

First, thanks for being a second set of eyes.  It really helps to go over things for a sanity check. 

You are exactly right.  M == self and t will be the buttonGroup when the event is fired.  antecedent connects the 2 when events are called by corona for groups and images.  I am pretty sure all this is straight.  This button stuff works perfectly if it isn’t on top of a tableView.  It is even working in games that are currently in the app store.  Now I wondering if my tableView code is issuing the same set focus stuff and stealing it away.  I am going to check that next.   

I guess that is the catch 22 of setting focus.  If every touch listener does it then it really isn’t doing it.  

but if your button is successfully getting focus for that event, then tableview should even get the chance to steal it.

about all i can think to suggest is try some simpler code, see if it works properly, if so then try to figure out any differences.  for example:

-- SETUP: display.setStatusBar( display.HiddenStatusBar ) local widget = require( "widget" ) local SOX, SOY = display.screenOriginX, display.screenOriginY local ACW, ACH = display.actualContentWidth, display.actualContentHeight -- TABLE VIEW: local tableView = widget.newTableView({ left=SOX, top=SOY, width=ACW, height=ACH, listener = function(event) print("tableview listener", event.phase) return true end, onRowRender = function(event) print("onRowRender", event.row.index) display.newText({parent=event.row, text=event.row.index, x=20, y=10, fontSize=10}):setFillColor(0) end, onRowTouch = function(event) print("onRowTouch", event.row.index, event.phase) return true end, }) for i = 1,50 do tableView:insertRow({ isCategory=(i%10==1), rowHeight=20, }) end -- BUTTON: local button = display.newCircle(SOX+ACW-40,SOY+ACH-40,20,20) button:setFillColor(1,0,1) button.tap = function(self, event) -- don't care, use touch instead, just eat it print("button.tap") return true end button:addEventListener("tap") button.touch = function(self, event) print("button.touch", event.phase) if (event.phase=="began") then display.getCurrentStage():setFocus(event.target) event.target.hasFocus = true event.target.xScale = 1.1 -- just for visual feedback event.target.yScale = 1.1 elseif (event.target.hasFocus) then if (event.phase == "moved") then -- do something? elseif (event.phase == "ended") or (event.phase == "cancelled") then display.getCurrentStage():setFocus(nil) event.target.hasFocus = false event.target.xScale = 1 -- just for visual feedback event.target.yScale = 1 end end return true end button:addEventListener("touch")

(i don’t know how closely that mimics your setup, but just as a point of beginning to ask:  do the events happen as you wish/expect?)

Are you returning true after handing the touch event?

Rob

I wasn’t, so I changed it to this:  Does it look right?  I get the first “began” and nothing else.  

function M:touch\_listener( event ) local event = event local t = event.target local self = t.antecedent -- local sfx = GlblData.soundobject -- sound effects print ("button touch listener", event.phase , self , event.id ) if self then -- this listener was being called after the listener was removed and self:destroy was called. So things were failing. if self.buttonGroup.whichimage ~= "inactive" then if event.phase == "began" then self:begin\_rollover() if event.id then display.getCurrentStage():setFocus(event.target, event.id) end t.isFocus = true local uiEvent = {name = "onUIevent", phase = "pressed", buttonName = self.buttonName or "none" , target = t } Runtime:dispatchEvent(uiEvent) elseif ( event.phase == "moved" ) then self:begin\_rollover() self:rollovertimebump() -- bump out time to stay in rollover mode. elseif ( event.phase == "ended" or event.phase == "cancelled" ) then self:begin\_main() if event.id then display.getCurrentStage():setFocus(nil, event.id) end t.isFocus = false local uiEvent = {name = "onUIevent", phase = "released", buttonName = self.buttonName or "none" , target = t } print ("release event dispatched ", event.phase ) Runtime:dispatchEvent(uiEvent) end -- "ended" end end return true end

what happens in the various “rollover” code?  are you potentially swapping images?  any chance you’re setting focus on the wrong (hidden) one?

I have a displayGroup for 4 button images. (main, clicked, rollover, inactive ) I am swapping the images around depending on which one I want in front.  The touch listener is only on the DG.  

function M:addlistener( ) self.buttonGroup.touch = self.touch\_listener self.buttonGroup:addEventListener( "touch" , self.buttonGroup ) return end 

This is the main part of the rollover code.  

 self.image\_rollover.isVisible = true self.image\_inactive.isVisible = false self.image\_clicked.isVisible = false self.image.isVisible = false self.buttonGroup:insert(self.image\_rollover) -- put image on top

then i’d look around for consistent use of “self” and/or “buttonGroup”, for example:

 if self.buttonGroup.whichimage ~= "inactive" then 

seems suspect.  inside the listener, where M.touch_listener was assigned to buttonGroup.touch, “self” will refer to the same thing as event.target (ie the button group).  that code looks like you’re using “self” to mean “M”, but it won’t be (at least, not when called as the buttonGroup’s listener)  is that what “t.antecedant” is supposed to be resolving?  (it’s a bit difficult to follow given just snippets)

First, thanks for being a second set of eyes.  It really helps to go over things for a sanity check. 

You are exactly right.  M == self and t will be the buttonGroup when the event is fired.  antecedent connects the 2 when events are called by corona for groups and images.  I am pretty sure all this is straight.  This button stuff works perfectly if it isn’t on top of a tableView.  It is even working in games that are currently in the app store.  Now I wondering if my tableView code is issuing the same set focus stuff and stealing it away.  I am going to check that next.   

I guess that is the catch 22 of setting focus.  If every touch listener does it then it really isn’t doing it.  

but if your button is successfully getting focus for that event, then tableview should even get the chance to steal it.

about all i can think to suggest is try some simpler code, see if it works properly, if so then try to figure out any differences.  for example:

-- SETUP: display.setStatusBar( display.HiddenStatusBar ) local widget = require( "widget" ) local SOX, SOY = display.screenOriginX, display.screenOriginY local ACW, ACH = display.actualContentWidth, display.actualContentHeight -- TABLE VIEW: local tableView = widget.newTableView({ left=SOX, top=SOY, width=ACW, height=ACH, listener = function(event) print("tableview listener", event.phase) return true end, onRowRender = function(event) print("onRowRender", event.row.index) display.newText({parent=event.row, text=event.row.index, x=20, y=10, fontSize=10}):setFillColor(0) end, onRowTouch = function(event) print("onRowTouch", event.row.index, event.phase) return true end, }) for i = 1,50 do tableView:insertRow({ isCategory=(i%10==1), rowHeight=20, }) end -- BUTTON: local button = display.newCircle(SOX+ACW-40,SOY+ACH-40,20,20) button:setFillColor(1,0,1) button.tap = function(self, event) -- don't care, use touch instead, just eat it print("button.tap") return true end button:addEventListener("tap") button.touch = function(self, event) print("button.touch", event.phase) if (event.phase=="began") then display.getCurrentStage():setFocus(event.target) event.target.hasFocus = true event.target.xScale = 1.1 -- just for visual feedback event.target.yScale = 1.1 elseif (event.target.hasFocus) then if (event.phase == "moved") then -- do something? elseif (event.phase == "ended") or (event.phase == "cancelled") then display.getCurrentStage():setFocus(nil) event.target.hasFocus = false event.target.xScale = 1 -- just for visual feedback event.target.yScale = 1 end end return true end button:addEventListener("touch")

(i don’t know how closely that mimics your setup, but just as a point of beginning to ask:  do the events happen as you wish/expect?)