Flick gesture

My situation is this:

I have a bunch of items drawn on display group that goes far below the screen size. I can scroll this up and down by dragging a finger up and down the screen. This works perfectly today…

Bu the item list has grown lately, and I’ve had to implement a “flick gesture support” so that I can set the list in motion by itself by “flicking” up/down.

I have tried to do this the following way:

In the touch handler I calculate the difference (deltaY) between the two latest y positions (of the finger) in the 

“moved” phase (before entering the “ended” phase). This I use to calculate the (auto) scroll speed that I use to scroll the items automatically after the flick gesture.

To slow down the scrolling I simply ad/subtract the scrollSpeed variable with 1 for each frame.

Problem is that this seems to work perfectly in the simulator, but on a device (Android) sometimes the flick gesture does not set the scrolling in motion at all and other times a careful flick creates a speed demon of a scroller…

I have two questions:

  1. Can anybody see if there are some bad things going on in my code that should result in this behavior?

(code below)

  1. Is there some built in functionality in Corona to help me with this stuff? I’ve tried to google “corona flick gesture” but there seems to be all questions and not too many answers.

I’m sorry about the many lines, but I’ve just extracted the lines from the main app and simplified it. 

display.setStatusBar( display.HiddenStatusBar ) local w = display.contentWidth local h = display.contentHeight -- Misc variables local mainGroup = display.newGroup() local yOffs = 0; local maxYOffs = (h - 4000) local scrollSpeedY=0 local deltaY=0 local lastMoveY=0 -- Paint 30 rectangles with alternating colors downwards a bit for idx = 1, 30 do &nbsp;&nbsp;&nbsp;&nbsp;local cY = idx \* 200 &nbsp;&nbsp;&nbsp;&nbsp;local bgRect = display.newRect(mainGroup, w/2, cY, w, 200) &nbsp;&nbsp;&nbsp;&nbsp;if (idx % 2 == 1) then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bgRect:setFillColor(0) &nbsp;&nbsp;&nbsp;&nbsp;else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bgRect:setFillColor(0.5 + 0.03\*idx) &nbsp;&nbsp;&nbsp;&nbsp;end end -- Touch handler local touchHandler = function(e) &nbsp;&nbsp;&nbsp;&nbsp;if (e.phase == "began") then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;scrollSpeedY = 0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;deltaY = 0 &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (e.phase == "moved") then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-- Calc delta Y, the pixel difference in position between the last move and this move &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;deltaY = e.y - lastMoveY &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lastMoveY = e.y &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-- Move main group according to the y-offset &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mainGroup.y = math.min(0, yOffs + (e.y - e.yStart)) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (mainGroup.y \< maxYOffs) then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mainGroup.y = maxYOffs &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;if (e.phase == "ended") then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;yOffs = mainGroup.y &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;scrollSpeedY = deltaY\*2 &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;return true end local frameRedrawListener = function(e) &nbsp;&nbsp;&nbsp;&nbsp;-- Keep on scrolling if scroll speed is large enough &nbsp;&nbsp;&nbsp;&nbsp;if (math.abs(scrollSpeedY) \> 0.5) then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mainGroup.y = math.min(0, yOffs + scrollSpeedY) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (mainGroup.y \< maxYOffs) then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mainGroup.y = maxYOffs &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;yOffs = mainGroup.y &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (scrollSpeedY \< 0) then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;scrollSpeedY = scrollSpeedY + 1 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;scrollSpeedY = scrollSpeedY - 1 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;end end Runtime:addEventListener( "enterFrame", frameRedrawListener ) Runtime:addEventListener( "touch", touchHandler )&nbsp;

I have, BTW, also tried implementing a similar example with the scrollView widget and to my great surprise the behaviour on my Android phone is almost the exact same as my DIY flick gesture code:

  • The scroll speed does not seem to follow the speed of the flick gesture

  • Sometimes the scrolling abruptly stops instead of continuing after the flick

  • Sometimes the scrolling seems to “bounce back” and the scrolling goes the wrong way after a flick

Here’s the code example using the scrollView widget:

local widget = require( "widget" ) display.setStatusBar( display.HiddenStatusBar ) local w = display.contentWidth local h = display.contentHeight -- ScrollView listener local function scrollListener( event ) local phase = event.phase if ( phase == "began" ) then print( "Scroll view was touched" ) &nbsp; elseif ( phase == "moved" ) then print( "Scroll view was moved" ) &nbsp; elseif ( phase == "ended" ) then print( "Scroll view was released" ) &nbsp; end &nbsp; -- In the event a scroll limit is reached... &nbsp; if ( event.limitReached ) then &nbsp; if ( event.direction == "up" ) then print( "Reached top limit" ) &nbsp; &nbsp; &nbsp;elseif ( event.direction == "down" ) then print( "Reached bottom limit" ) &nbsp; &nbsp; &nbsp;elseif ( event.direction == "left" ) then print( "Reached left limit" ) &nbsp; &nbsp; &nbsp;elseif ( event.direction == "right" ) then print( "Reached right limit" ) &nbsp; &nbsp; &nbsp;end end &nbsp; &nbsp;return true end -- Create the widget local scrollView = widget.newScrollView { x = w/2,y = h/2, &nbsp; &nbsp;width = w, height = h, &nbsp; &nbsp;scrollHeight = 4000, &nbsp;&nbsp;&nbsp;horizontalScrollDisabled = true, &nbsp;&nbsp;&nbsp;hideBackground = true, &nbsp; &nbsp;listener = scrollListener } local background = display.newImageRect( "image.png", w/2, 4000 ) background.x = w/2 background.y = 2000 scrollView:insert( background )&nbsp;

I have, BTW, also tried implementing a similar example with the scrollView widget and to my great surprise the behaviour on my Android phone is almost the exact same as my DIY flick gesture code:

  • The scroll speed does not seem to follow the speed of the flick gesture

  • Sometimes the scrolling abruptly stops instead of continuing after the flick

  • Sometimes the scrolling seems to “bounce back” and the scrolling goes the wrong way after a flick

Here’s the code example using the scrollView widget:

local widget = require( "widget" ) display.setStatusBar( display.HiddenStatusBar ) local w = display.contentWidth local h = display.contentHeight -- ScrollView listener local function scrollListener( event ) local phase = event.phase if ( phase == "began" ) then print( "Scroll view was touched" ) &nbsp; elseif ( phase == "moved" ) then print( "Scroll view was moved" ) &nbsp; elseif ( phase == "ended" ) then print( "Scroll view was released" ) &nbsp; end &nbsp; -- In the event a scroll limit is reached... &nbsp; if ( event.limitReached ) then &nbsp; if ( event.direction == "up" ) then print( "Reached top limit" ) &nbsp; &nbsp; &nbsp;elseif ( event.direction == "down" ) then print( "Reached bottom limit" ) &nbsp; &nbsp; &nbsp;elseif ( event.direction == "left" ) then print( "Reached left limit" ) &nbsp; &nbsp; &nbsp;elseif ( event.direction == "right" ) then print( "Reached right limit" ) &nbsp; &nbsp; &nbsp;end end &nbsp; &nbsp;return true end -- Create the widget local scrollView = widget.newScrollView { x = w/2,y = h/2, &nbsp; &nbsp;width = w, height = h, &nbsp; &nbsp;scrollHeight = 4000, &nbsp;&nbsp;&nbsp;horizontalScrollDisabled = true, &nbsp;&nbsp;&nbsp;hideBackground = true, &nbsp; &nbsp;listener = scrollListener } local background = display.newImageRect( "image.png", w/2, 4000 ) background.x = w/2 background.y = 2000 scrollView:insert( background )&nbsp;