Touch Event - Detecting touched/no longer touched objects

Hi guys!

I have 3 text lines for which I have set a touch event listener.

I would like that when :

  • When the touch begins, the touched object scales up (2x)
  • When it is no longer touched, it reverts to its previous state (1x)
  • When in a single touch + drag over the lines, only the currently selected object is scaled

I tried the following, but I’m unsure if it the best route to accomplish this (I don’t like it…)

I’d appreciate any an all insight, help, feedback!

Thanks!
S.

[code]
local currentlyTouchedObject

local function onOptionTouched( self, event )
if currentlyTouchedObject == nil then
currentlyTouchedObject = event.target
elseif currentlyTouchedObject ~= event.target then
print( “NOT EQUAL” )
currentlyTouchedObject:scale(0.5, 0.5)
currentlyTouchedObject = event.target
event.target:scale(2.0, 2.0)
end

if event.phase == “began” then
event.target:scale(2.0, 2.0)
elseif event.phase == “ended” or event.phase == “cancelled” then
event.target:scale(0.5, 0.5)
elseif event.phase == “moved” then
– return false
end
return true

end

local option1 = display.newText( “Option 1”, 0, 0, native.systemFont, 18 )
option1:setReferencePoint(display.TopLeftReferencePoint)
option1.x = actor.contentWidth
option1.y = display.contentHeight - actor.contentHeight
option1.tag = 1
option1.touch = onOptionTouched
option1:addEventListener( “touch”, option1)

local option2 = display.newText( “Option 2”, 0, 0, native.systemFont, 18 )
option2:setReferencePoint(display.TopLeftReferencePoint)
option2.x = actor.contentWidth + 40
option2.y = display.contentHeight - actor.contentHeight + 40
option2.tag = 2
option2.touch = onOptionTouched
option2:addEventListener( “touch”, option2)

local option3 = display.newText( “Option 3”, 0, 0, native.systemFont, 18 )
option3:setReferencePoint(display.TopLeftReferencePoint)
option3.x = actor.contentWidth + 80
option3.y = display.contentHeight - actor.contentHeight + 80
option3.tag = 3
option3.touch = onOptionTouched
option3:addEventListener( “touch”, option3)

[/code] [import]uid: 133444 topic_id: 30286 reply_id: 330286[/import]

I’m not sure what the difference between the first two states and the third is. Could you describe “When in a single touch + drag over the lines, only the currently selected object is scaled” a bit more, please? [import]uid: 8271 topic_id: 30286 reply_id: 121332[/import]

I’ll try to be clearer :slight_smile:

By single touch + drag over I mean: tapping on an item and then without lifting your finger dragging down on the items below.

So, If I tap on “Option 1” and drag down over to “Option 3”, while the finger is moving down I’d expect:

  • “Option 1” to be at 2x (all others should be at default 1x)
  • When the tap/drag down goes over “Option 2”, then “Option 1” would revert to 1x and “Option 2” would be at 2x
  • Then when the tap/drag down goes over “Option 3”, then “Option 2” would revert to 1x and “Option 3” would be at 2x

The goal is to highlight the currently selected item.

S. [import]uid: 133444 topic_id: 30286 reply_id: 121333[/import]

I continued testing things out and came up with the following, but I’m not sure if that’s the correct approach… (I know there’s a lot of redundancy, this is a test :slight_smile: )

[code]
local currentlyTouchedObject

local function onOptionTouched( self, event )

if (currentlyTouchedObject == nil) then
currentlyTouchedObject = dialogSelectItem(event.target)

elseif (currentlyTouchedObject ~= event.target) then

currentlyTouchedObject = dialogDeselectItem(currentlyTouchedObject)
currentlyTouchedObject = dialogSelectItem(event.target)
end

if event.phase == “began” then
print(event.phase)

elseif event.phase == “ended” or event.phase == “cancelled” then
print(event.phase)
print( event.target.tag … " was selected" )
elseif event.phase == “moved” then

end

return true

end

function dialogSelectItem( item )

local txt = item.text
local left = item.contentBounds.xMin
local top = item.contentBounds.yMin
local tag = item.tag

item:removeSelf()

item = display.newText( txt, left, top, native.systemFont, 35)
item:setReferencePoint(display.TopLeftReferencePoint)
item.tag = tag
item.touch = onOptionTouched
item:addEventListener( “touch”, item)

return item

end

function dialogDeselectItem( item )

local txt = item.text
local left = item.contentBounds.xMin
local top = item.contentBounds.yMin
local tag = item.tag

item:removeSelf()

item = display.newText( txt, left, top, native.systemFont, 18)
item:setReferencePoint(display.TopLeftReferencePoint)
item.tag = tag
item.touch = onOptionTouched
item:addEventListener( “touch”, item)

return item

end
[/code] [import]uid: 133444 topic_id: 30286 reply_id: 121334[/import]

So you just want to highlight whichever item has the touch over it? Could you post a complete solution so I can see what you’re trying to do at present? [import]uid: 8271 topic_id: 30286 reply_id: 121357[/import]

Here’s what I had in mind (I hope I’m allowed to post long code samples…):

S.

[code]
display.setStatusBar( display.HiddenStatusBar)

– Containing Group
local optionGroup = display.newGroup()

– Test Items
local option1
local option2
local option3

function main()
setup()
end

local currentlyTouchedObject

local function onOptionTouched( self, event )

if (currentlyTouchedObject == nil) then
currentlyTouchedObject = event.target
end
if (currentlyTouchedObject ~= event.target) then
currentlyTouchedObject = updateItem(currentlyTouchedObject, event.target)
end

if event.phase == “began” then
currentlyTouchedObject = configureItem(currentlyTouchedObject, 35)

elseif event.phase == “moved” then
return false
elseif event.phase == “ended” or event.phase == “cancelled” then
print( “Option " … event.target.tag … " was selected” )
end

return true

end
function setup()

– Title
local title = display.newText(“Sample Items”, 0, 0, native.systemFont, 16)
title.align = “center”
title:setReferencePoint(display.BottomLeftReferencePoint)
title.x = 100
title.y = 80

option1 = display.newText( “Lipsum Text 1”, 0, 0, native.systemFont, 24 )
option1:setReferencePoint(display.CenterLeftReferencePoint)
option1.x = 100
option1.y = 100
option1.tag = 1
option1.touch = onOptionTouched
option1:addEventListener( “touch”, option1)

option2 = display.newText( “Lipsum Text 2”, 0, 0, native.systemFont, 24 )
option2:setReferencePoint(display.CenterLeftReferencePoint)
option2.x = 100
option2.y = 140
option2.tag = 2
option2.touch = onOptionTouched
option2:addEventListener( “touch”, option2)

option3 = display.newText( “Lipsum Text 3”, 0, 0, native.systemFont, 24 )
option3:setReferencePoint(display.CenterLeftReferencePoint)
option3.x = 100
option3.y = 180
option3.tag = 3
option3.touch = onOptionTouched
option3:addEventListener( “touch”, option3)

optionGroup:insert( option1 )
optionGroup:insert( option2 )
optionGroup:insert( option3 )

end

function updateItem( item, newItem )
– Change Font size of previous selected item
– currentlyTouchedObject
configureItem(item, 24)

– Return new selected item
return configureItem(newItem, 35);

end

function configureItem(item, fontSize)
local _text = item.text
local _x = item.x
local _y = item.y

local tag = item.tag

item:removeSelf()

item = display.newText( _text, 0, 0, native.systemFont, fontSize)
item:setReferencePoint(display.CenterLeftReferencePoint)
item.x = _x
item.y = _y
item.tag = tag
item.touch = onOptionTouched
item:addEventListener( “touch”, item)

return item

end

main()
[/code] [import]uid: 133444 topic_id: 30286 reply_id: 121360[/import]

Hey, is this what you want?
main.lua:
[lua]local stage = display.getCurrentStage()

– listen to text to scale up or down when touching text
function touch( e )
if (e.phase == “began” or e.phase == “moved”) then
– scale up when touching text
for i=1, stage.numChildren do
if (e.target.class == “text”) then
– only scale the text being touched
if (stage[i] == e.target) then
stage[i].xScale, stage[i].yScale = 2, 2
else
stage[i].xScale, stage[i].yScale = 1, 1
end
end
end
else
– scale down all text when touch ends (or cancelled)
for i=1, stage.numChildren do
stage[i].xScale, stage[i].yScale = 1, 1
end
end
return true
end

– create a text
function newText( txt, x, y, name )
local a = display.newText( txt, 0, 0, native.systemFont, 35)
a.x, a.y = x, y
a.isText = true
a.class = “text”
a.name = name
a:addEventListener( “touch”, touch )
return a
end

local a = newText( “The first text”, display.contentCenterX, 100, “first” )
local b = newText( “The second text”, display.contentCenterX, 150, “second” )
local c = newText( “The third text”, display.contentCenterX, 200, “third” )

– listen to the runtime to scale down when not touching text
function runTouch( e )
for i=1, stage.numChildren do
stage[i].xScale, stage[i].yScale = 1, 1
end
return true
end

Runtime:addEventListener( “touch”, runTouch )[/lua] [import]uid: 8271 topic_id: 30286 reply_id: 121381[/import]

Yes it is :slight_smile: I will now study what you did there! Thanks! [import]uid: 133444 topic_id: 30286 reply_id: 121385[/import]

Hi again, I’d like to pick your brain further :slight_smile:

What if I wanted to change the font size as opposed to the scaling. It seems that Corona can’t just update the font size, but needs to recreated the display object.

In the following code, I added the items to a display group, and I’m trying to regenerate the text objects when needed. I have an error message, which I assume is due to the the modified numChildren count in the group?

[code]
display.setStatusBar( display.HiddenStatusBar)

local stage = display.getCurrentStage()
local optionGroup = display.newGroup()

local function main()
setup()
end
local function onOptionTouched( e )

if (e.phase == “began” or e.phase == “moved”) then
for i=1, optionGroup.numChildren do
if (e.target.class == “text”) then
if (optionGroup[i] == e.target) then
local selectedItem = optionGroup[i]
optionGroup[i]:removeSelf()
optionGroup[i] = newText( selectedItem.text, selectedItem.x, selectedItem.y, selectedItem.name, 48)

else
local selectedItem = optionGroup[i]
optionGroup[i]:removeSelf()
optionGroup[i] = newText( selectedItem.text, selectedItem.x, selectedItem.y, selectedItem.name, 24)
end
end
end
end
return true
end

– create a text
function newText( txt, x, y, name, fontSize )
local a = display.newText( txt, 0, 0, native.systemFont, fontSize)
a:setReferencePoint(display.CenterLeftReferencePoint)
a.x, a.y = x, y
a.isText = true
a.class = “text”
a.name = name
a:addEventListener( “touch”, onOptionTouched )
return a
end

function setup()
– Title
local title = display.newText(“Sample Items”, 0, 0, native.systemFont, 16)
title.align = “center”
title:setReferencePoint(display.BottomLeftReferencePoint)
title.x = 100
title.y = 80

local option1 = newText(“Lipsum 1”, 100, 100, “one”, 24)
local option2 = newText(“Lipsum 2”, 100, 140, “two”, 24)
local option3 = newText(“Lipsum 3”, 100, 180, “three”, 24)

optionGroup:insert( option1 )
optionGroup:insert( option2 )
optionGroup:insert( option3 )

end

main()
[/code] [import]uid: 133444 topic_id: 30286 reply_id: 121403[/import]

Yes, you’ll need to regen the text objects because, once rendered, they are graphics images.

What’s the error?

It looks like you are trying to remove the text without (a) removing the touch listener first and (b) by looping 1,2,3 when you should be going the other way.

The for loop is now wrong because by the time it tries to remove the item at index 3 it has already been removed. Try this:
[lua]for i=optionGroup.numChildren, 1, -1 do[/lua] [import]uid: 8271 topic_id: 30286 reply_id: 121469[/import]

I’m not sure what the difference between the first two states and the third is. Could you describe “When in a single touch + drag over the lines, only the currently selected object is scaled” a bit more, please? [import]uid: 8271 topic_id: 30286 reply_id: 121332[/import]

I’ll try to be clearer :slight_smile:

By single touch + drag over I mean: tapping on an item and then without lifting your finger dragging down on the items below.

So, If I tap on “Option 1” and drag down over to “Option 3”, while the finger is moving down I’d expect:

  • “Option 1” to be at 2x (all others should be at default 1x)
  • When the tap/drag down goes over “Option 2”, then “Option 1” would revert to 1x and “Option 2” would be at 2x
  • Then when the tap/drag down goes over “Option 3”, then “Option 2” would revert to 1x and “Option 3” would be at 2x

The goal is to highlight the currently selected item.

S. [import]uid: 133444 topic_id: 30286 reply_id: 121333[/import]

I continued testing things out and came up with the following, but I’m not sure if that’s the correct approach… (I know there’s a lot of redundancy, this is a test :slight_smile: )

[code]
local currentlyTouchedObject

local function onOptionTouched( self, event )

if (currentlyTouchedObject == nil) then
currentlyTouchedObject = dialogSelectItem(event.target)

elseif (currentlyTouchedObject ~= event.target) then

currentlyTouchedObject = dialogDeselectItem(currentlyTouchedObject)
currentlyTouchedObject = dialogSelectItem(event.target)
end

if event.phase == “began” then
print(event.phase)

elseif event.phase == “ended” or event.phase == “cancelled” then
print(event.phase)
print( event.target.tag … " was selected" )
elseif event.phase == “moved” then

end

return true

end

function dialogSelectItem( item )

local txt = item.text
local left = item.contentBounds.xMin
local top = item.contentBounds.yMin
local tag = item.tag

item:removeSelf()

item = display.newText( txt, left, top, native.systemFont, 35)
item:setReferencePoint(display.TopLeftReferencePoint)
item.tag = tag
item.touch = onOptionTouched
item:addEventListener( “touch”, item)

return item

end

function dialogDeselectItem( item )

local txt = item.text
local left = item.contentBounds.xMin
local top = item.contentBounds.yMin
local tag = item.tag

item:removeSelf()

item = display.newText( txt, left, top, native.systemFont, 18)
item:setReferencePoint(display.TopLeftReferencePoint)
item.tag = tag
item.touch = onOptionTouched
item:addEventListener( “touch”, item)

return item

end
[/code] [import]uid: 133444 topic_id: 30286 reply_id: 121334[/import]

So you just want to highlight whichever item has the touch over it? Could you post a complete solution so I can see what you’re trying to do at present? [import]uid: 8271 topic_id: 30286 reply_id: 121357[/import]

Here’s what I had in mind (I hope I’m allowed to post long code samples…):

S.

[code]
display.setStatusBar( display.HiddenStatusBar)

– Containing Group
local optionGroup = display.newGroup()

– Test Items
local option1
local option2
local option3

function main()
setup()
end

local currentlyTouchedObject

local function onOptionTouched( self, event )

if (currentlyTouchedObject == nil) then
currentlyTouchedObject = event.target
end
if (currentlyTouchedObject ~= event.target) then
currentlyTouchedObject = updateItem(currentlyTouchedObject, event.target)
end

if event.phase == “began” then
currentlyTouchedObject = configureItem(currentlyTouchedObject, 35)

elseif event.phase == “moved” then
return false
elseif event.phase == “ended” or event.phase == “cancelled” then
print( “Option " … event.target.tag … " was selected” )
end

return true

end
function setup()

– Title
local title = display.newText(“Sample Items”, 0, 0, native.systemFont, 16)
title.align = “center”
title:setReferencePoint(display.BottomLeftReferencePoint)
title.x = 100
title.y = 80

option1 = display.newText( “Lipsum Text 1”, 0, 0, native.systemFont, 24 )
option1:setReferencePoint(display.CenterLeftReferencePoint)
option1.x = 100
option1.y = 100
option1.tag = 1
option1.touch = onOptionTouched
option1:addEventListener( “touch”, option1)

option2 = display.newText( “Lipsum Text 2”, 0, 0, native.systemFont, 24 )
option2:setReferencePoint(display.CenterLeftReferencePoint)
option2.x = 100
option2.y = 140
option2.tag = 2
option2.touch = onOptionTouched
option2:addEventListener( “touch”, option2)

option3 = display.newText( “Lipsum Text 3”, 0, 0, native.systemFont, 24 )
option3:setReferencePoint(display.CenterLeftReferencePoint)
option3.x = 100
option3.y = 180
option3.tag = 3
option3.touch = onOptionTouched
option3:addEventListener( “touch”, option3)

optionGroup:insert( option1 )
optionGroup:insert( option2 )
optionGroup:insert( option3 )

end

function updateItem( item, newItem )
– Change Font size of previous selected item
– currentlyTouchedObject
configureItem(item, 24)

– Return new selected item
return configureItem(newItem, 35);

end

function configureItem(item, fontSize)
local _text = item.text
local _x = item.x
local _y = item.y

local tag = item.tag

item:removeSelf()

item = display.newText( _text, 0, 0, native.systemFont, fontSize)
item:setReferencePoint(display.CenterLeftReferencePoint)
item.x = _x
item.y = _y
item.tag = tag
item.touch = onOptionTouched
item:addEventListener( “touch”, item)

return item

end

main()
[/code] [import]uid: 133444 topic_id: 30286 reply_id: 121360[/import]

Hey, is this what you want?
main.lua:
[lua]local stage = display.getCurrentStage()

– listen to text to scale up or down when touching text
function touch( e )
if (e.phase == “began” or e.phase == “moved”) then
– scale up when touching text
for i=1, stage.numChildren do
if (e.target.class == “text”) then
– only scale the text being touched
if (stage[i] == e.target) then
stage[i].xScale, stage[i].yScale = 2, 2
else
stage[i].xScale, stage[i].yScale = 1, 1
end
end
end
else
– scale down all text when touch ends (or cancelled)
for i=1, stage.numChildren do
stage[i].xScale, stage[i].yScale = 1, 1
end
end
return true
end

– create a text
function newText( txt, x, y, name )
local a = display.newText( txt, 0, 0, native.systemFont, 35)
a.x, a.y = x, y
a.isText = true
a.class = “text”
a.name = name
a:addEventListener( “touch”, touch )
return a
end

local a = newText( “The first text”, display.contentCenterX, 100, “first” )
local b = newText( “The second text”, display.contentCenterX, 150, “second” )
local c = newText( “The third text”, display.contentCenterX, 200, “third” )

– listen to the runtime to scale down when not touching text
function runTouch( e )
for i=1, stage.numChildren do
stage[i].xScale, stage[i].yScale = 1, 1
end
return true
end

Runtime:addEventListener( “touch”, runTouch )[/lua] [import]uid: 8271 topic_id: 30286 reply_id: 121381[/import]

Yes it is :slight_smile: I will now study what you did there! Thanks! [import]uid: 133444 topic_id: 30286 reply_id: 121385[/import]

Hi again, I’d like to pick your brain further :slight_smile:

What if I wanted to change the font size as opposed to the scaling. It seems that Corona can’t just update the font size, but needs to recreated the display object.

In the following code, I added the items to a display group, and I’m trying to regenerate the text objects when needed. I have an error message, which I assume is due to the the modified numChildren count in the group?

[code]
display.setStatusBar( display.HiddenStatusBar)

local stage = display.getCurrentStage()
local optionGroup = display.newGroup()

local function main()
setup()
end
local function onOptionTouched( e )

if (e.phase == “began” or e.phase == “moved”) then
for i=1, optionGroup.numChildren do
if (e.target.class == “text”) then
if (optionGroup[i] == e.target) then
local selectedItem = optionGroup[i]
optionGroup[i]:removeSelf()
optionGroup[i] = newText( selectedItem.text, selectedItem.x, selectedItem.y, selectedItem.name, 48)

else
local selectedItem = optionGroup[i]
optionGroup[i]:removeSelf()
optionGroup[i] = newText( selectedItem.text, selectedItem.x, selectedItem.y, selectedItem.name, 24)
end
end
end
end
return true
end

– create a text
function newText( txt, x, y, name, fontSize )
local a = display.newText( txt, 0, 0, native.systemFont, fontSize)
a:setReferencePoint(display.CenterLeftReferencePoint)
a.x, a.y = x, y
a.isText = true
a.class = “text”
a.name = name
a:addEventListener( “touch”, onOptionTouched )
return a
end

function setup()
– Title
local title = display.newText(“Sample Items”, 0, 0, native.systemFont, 16)
title.align = “center”
title:setReferencePoint(display.BottomLeftReferencePoint)
title.x = 100
title.y = 80

local option1 = newText(“Lipsum 1”, 100, 100, “one”, 24)
local option2 = newText(“Lipsum 2”, 100, 140, “two”, 24)
local option3 = newText(“Lipsum 3”, 100, 180, “three”, 24)

optionGroup:insert( option1 )
optionGroup:insert( option2 )
optionGroup:insert( option3 )

end

main()
[/code] [import]uid: 133444 topic_id: 30286 reply_id: 121403[/import]

Yes, you’ll need to regen the text objects because, once rendered, they are graphics images.

What’s the error?

It looks like you are trying to remove the text without (a) removing the touch listener first and (b) by looping 1,2,3 when you should be going the other way.

The for loop is now wrong because by the time it tries to remove the item at index 3 it has already been removed. Try this:
[lua]for i=optionGroup.numChildren, 1, -1 do[/lua] [import]uid: 8271 topic_id: 30286 reply_id: 121469[/import]