Swipe Left Or Right To Change Scenes?

Hi,

I am wondering if there is a ‘nice way’ to implement a swipe left or right to change scenes?   Each scene has a scrollview widget in it so I had though of using slideleft and right built into this widget but this is less than satisfactory.  It appears quite jerky (there is a pause before it switches scene) and the objects on the scroll view appear to slide off the background (hard to explain)…

Thanks in advance,

Craig

Hi Craig,

There should be a few solutions in the Corona Code Exchange: http://developer.coronalabs.com/code/

I posted an iOS-like “swipe menu” in there some time ago; it hasn’t been updated in awhile, but should still be fully functional. It doesn’t swap scenes on swipe, but you can pull the swipe functionality and probably work that into Storyboard or Director.

Best regards,

Brent

Thanks Brent,  

I had a look at your code and as far as I can tell you are adding a ‘touch’ listener to the image,  I tried something like this (see code below if you want) but it doesn’t quite work.  I put a rectangle over the top of the screen with alpha set to 0 (would act the same as your image) and this works perfectly, however the only way to detect the moved state on the rectangle is to return true and this means that the touch is not passed through to the scrollview widget.  If I don’t return true then the scrollview works but no move state is detected on the rectangle.

I tried adding the rectangle behind as background but I cannot get the touch to pass through the scrollview widget.

I found another piece of code that looked promising where Mark Falkland had added the touch listener at runtime,  this works perfectly without the scrollview but doesn’t fire at all with the scrollview (it fires above and below it).

For now I am just using the scrollviews built in swipeLeft/Right (which looks jerky on my Android S2, runs perfectly on the simulator), if anyone else has an alternative solution I could try then I would appreciate it.

Thanks,

Craig

Here is my storyboard file…

local storyboard = require( "storyboard" ) local storyboardfile = storyboard.newScene() local widget = require("widget"); local font = "Helvetica" or system.nativeFont; display.setStatusBar(display.HiddenStatusBar ) -- Called when the scenes view does not exist: function storyboardfile:createScene( event ) scene = self.view local scene = scene local scrollView = widget.newScrollView { top = 41, left = 0, width = 300, height = 477, horizontalScrollDisabled = true, -- disable so I dont get the ugly swiping effect hideScrollBar = true, scrollWidth = 300, backgroundColor = { 197, 197, 197 }, -- bgColor =\> backgroundColor verticalScrollDisabled = false, -- scrollView.content.verticallScrollDisabled =\> verticalScrollDisabled listener = scrollListener, maskFile = "Assets/mask-320x477.png" } scene:insert(scrollView) for i = 1, 15 do -- Add rectangle fillers to scrollview local rect = display.newRect(0,70\*i,display.contentWidth,70) rect:setFillColor ( 20\*i) scrollView:insert( rect ) end --layer to detect swipes local swipeLayer = display.newRect(scene, 0, 0, display.contentWidth, display.contentHeight ) swipeLayer.alpha=0 --make it transparent swipeLayer.isHitTestable = true local function startDrag(event) local swipeLength = math.abs(event.x - event.xStart) print(event.phase, swipeLength) local t = event.target local phase = event.phase if "began" == phase then return true elseif "moved" == phase then elseif "ended" == phase or "cancelled" == phase then if event.xStart \> event.x and swipeLength \> 50 then print("Swiped Left") elseif event.xStart \< event.x and swipeLength \> 50 then print( "Swiped Right" ) end end end swipeLayer:addEventListener("touch", startDrag) -- if you comment out his line then the scrollview will work end -- Called immediately after scene has moved onscreen: function storyboardfile:enterScene( event ) scene = self.view local scene = scene local lastScene = storyboard.getPrevious() if(lastScene) then storyboard.purgeScene( lastScene ) end -- INSERT code here (e.g. start timers, load audio, start listeners, etc.) end -- Called when scene is about to move offscreen: function storyboardfile:exitScene( event ) scene = self.view end -- Called prior to the removal of scenes "view" (display group) function storyboardfile:destroyScene( event ) scene = self.view end --------------------------------------------------------------------------------- -- END OF YOUR IMPLEMENTATION --------------------------------------------------------------------------------- -- "createScene" event is dispatched if scenes view does not exist storyboardfile:addEventListener( "createScene", storyboardfile ) -- "enterScene" event is dispatched whenever scene transition has finished storyboardfile:addEventListener( "enterScene", storyboardfile ) -- "exitScene" event is dispatched before next scenes transition begins storyboardfile:addEventListener( "exitScene", storyboardfile ) -- "destroyScene" event is dispatched before view is unloaded, which can be -- automatically unloaded in low memory situations, or explicitly via a call to -- storyboard.purgeScene() or storyboard.removeScene(). storyboardfile:addEventListener( "destroyScene", storyboardfile ) --------------------------------------------------------------------------------- return storyboardfile

Hi Craig,

There should be a few solutions in the Corona Code Exchange: http://developer.coronalabs.com/code/

I posted an iOS-like “swipe menu” in there some time ago; it hasn’t been updated in awhile, but should still be fully functional. It doesn’t swap scenes on swipe, but you can pull the swipe functionality and probably work that into Storyboard or Director.

Best regards,

Brent

Thanks Brent,  

I had a look at your code and as far as I can tell you are adding a ‘touch’ listener to the image,  I tried something like this (see code below if you want) but it doesn’t quite work.  I put a rectangle over the top of the screen with alpha set to 0 (would act the same as your image) and this works perfectly, however the only way to detect the moved state on the rectangle is to return true and this means that the touch is not passed through to the scrollview widget.  If I don’t return true then the scrollview works but no move state is detected on the rectangle.

I tried adding the rectangle behind as background but I cannot get the touch to pass through the scrollview widget.

I found another piece of code that looked promising where Mark Falkland had added the touch listener at runtime,  this works perfectly without the scrollview but doesn’t fire at all with the scrollview (it fires above and below it).

For now I am just using the scrollviews built in swipeLeft/Right (which looks jerky on my Android S2, runs perfectly on the simulator), if anyone else has an alternative solution I could try then I would appreciate it.

Thanks,

Craig

Here is my storyboard file…

local storyboard = require( "storyboard" ) local storyboardfile = storyboard.newScene() local widget = require("widget"); local font = "Helvetica" or system.nativeFont; display.setStatusBar(display.HiddenStatusBar ) -- Called when the scenes view does not exist: function storyboardfile:createScene( event ) scene = self.view local scene = scene local scrollView = widget.newScrollView { top = 41, left = 0, width = 300, height = 477, horizontalScrollDisabled = true, -- disable so I dont get the ugly swiping effect hideScrollBar = true, scrollWidth = 300, backgroundColor = { 197, 197, 197 }, -- bgColor =\> backgroundColor verticalScrollDisabled = false, -- scrollView.content.verticallScrollDisabled =\> verticalScrollDisabled listener = scrollListener, maskFile = "Assets/mask-320x477.png" } scene:insert(scrollView) for i = 1, 15 do -- Add rectangle fillers to scrollview local rect = display.newRect(0,70\*i,display.contentWidth,70) rect:setFillColor ( 20\*i) scrollView:insert( rect ) end --layer to detect swipes local swipeLayer = display.newRect(scene, 0, 0, display.contentWidth, display.contentHeight ) swipeLayer.alpha=0 --make it transparent swipeLayer.isHitTestable = true local function startDrag(event) local swipeLength = math.abs(event.x - event.xStart) print(event.phase, swipeLength) local t = event.target local phase = event.phase if "began" == phase then return true elseif "moved" == phase then elseif "ended" == phase or "cancelled" == phase then if event.xStart \> event.x and swipeLength \> 50 then print("Swiped Left") elseif event.xStart \< event.x and swipeLength \> 50 then print( "Swiped Right" ) end end end swipeLayer:addEventListener("touch", startDrag) -- if you comment out his line then the scrollview will work end -- Called immediately after scene has moved onscreen: function storyboardfile:enterScene( event ) scene = self.view local scene = scene local lastScene = storyboard.getPrevious() if(lastScene) then storyboard.purgeScene( lastScene ) end -- INSERT code here (e.g. start timers, load audio, start listeners, etc.) end -- Called when scene is about to move offscreen: function storyboardfile:exitScene( event ) scene = self.view end -- Called prior to the removal of scenes "view" (display group) function storyboardfile:destroyScene( event ) scene = self.view end --------------------------------------------------------------------------------- -- END OF YOUR IMPLEMENTATION --------------------------------------------------------------------------------- -- "createScene" event is dispatched if scenes view does not exist storyboardfile:addEventListener( "createScene", storyboardfile ) -- "enterScene" event is dispatched whenever scene transition has finished storyboardfile:addEventListener( "enterScene", storyboardfile ) -- "exitScene" event is dispatched before next scenes transition begins storyboardfile:addEventListener( "exitScene", storyboardfile ) -- "destroyScene" event is dispatched before view is unloaded, which can be -- automatically unloaded in low memory situations, or explicitly via a call to -- storyboard.purgeScene() or storyboard.removeScene(). storyboardfile:addEventListener( "destroyScene", storyboardfile ) --------------------------------------------------------------------------------- return storyboardfile

I did the rectangle method as well. I just made my rectangle have an alpha=0.01. Basically invisible, but then still handles touch events appropriately.

Setting the alpha=0.0, the rectangle doesn’t respond anymore.

I did the rectangle method as well. I just made my rectangle have an alpha=0.01. Basically invisible, but then still handles touch events appropriately.

Setting the alpha=0.0, the rectangle doesn’t respond anymore.

late to the party but for anyone else who reads this, if you want an invisible object to still respond to touch listeners, add this bit in the code:

theObject.isHitTestable = true

http://docs.coronalabs.com/api/type/DisplayObject/isHitTestable.html

I came up this a long time ago in StoryBoard seems to work for me.

Just add this function at the top of storyboard…on every page.

[lua]local function onSceneTouch( self, event )
if event.phase == “ended” then
if event.xStart < event.x and (event.x - event.xStart) >= 100 then
audio.play( pageturnSound )
storyboard.gotoScene( “page06”, “slideRight”, 1000 )
return true
end
elseif event.xStart > event.x and (event.xStart - event.x) >= 100 then
audio.play( pageturnSound )
storyboard.gotoScene( “page08”, “slideLeft”, 1000 )
return true
end
end[/lua]

late to the party but for anyone else who reads this, if you want an invisible object to still respond to touch listeners, add this bit in the code:

theObject.isHitTestable = true

http://docs.coronalabs.com/api/type/DisplayObject/isHitTestable.html

I came up this a long time ago in StoryBoard seems to work for me.

Just add this function at the top of storyboard…on every page.

[lua]local function onSceneTouch( self, event )
if event.phase == “ended” then
if event.xStart < event.x and (event.x - event.xStart) >= 100 then
audio.play( pageturnSound )
storyboard.gotoScene( “page06”, “slideRight”, 1000 )
return true
end
elseif event.xStart > event.x and (event.xStart - event.x) >= 100 then
audio.play( pageturnSound )
storyboard.gotoScene( “page08”, “slideLeft”, 1000 )
return true
end
end[/lua]