Skip to content

Instantly share code, notes, and snippets.

@HoraceBury
Created December 30, 2016 14:48
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save HoraceBury/eeab199c040673f04d391ae744ee2ea3 to your computer and use it in GitHub Desktop.
Save HoraceBury/eeab199c040673f04d391ae744ee2ea3 to your computer and use it in GitHub Desktop.
Provides a scrollview widget which can have items dragged off it.
local widget = require("widget")
local function angleOf( ax, ay, bx, by, adjust, positive )
local angle = math.atan2( by-ay, bx-ax ) * 180/math.pi
if (adjust) then
if (type(adjust) ~= "number") then adjust = -90 end
angle = angle - adjust
if (angle < -180) then angle=angle+360 end
if (angle > 180) then angle=angle-360 end
end
if (positive) then
if (angle < 0) then
angle = angle + 360
elseif (angle > 360) then
angle = angle - 360
end
end
return angle
end
local function lengthOf( ax, ay, bx, by )
local width, height = bx-ax, by-ay
return (width*width + height*height) ^ 0.5 -- math.sqrt(width*width + height*height)
end
function widget.newDragItemsScrollView( params )
local scrollview = widget.newScrollView( params )
function scrollview:add( item, listener, dragtime, angle, radius, touchthreshold )
scrollview:insert( item )
local dragtimer = nil
local touchevent = nil
local touch = nil
touchthreshold = touchthreshold or display.actualContentWidth*.1
local function isWithinRadius(e)
local angle = angleOf( e.xStart, e.yStart, e.x, e.y, angle-90, false )
return (angle > -radius/2 and angle < radius/2)
end
local function cancelDragTimer()
if (dragtimer) then
timer.cancel( dragtimer )
dragtimer = nil
end
end
local function startDragByHold()
print("start by hold")
item:removeEventListener( "touch", touch )
listener( item, touchevent )
item, touchevent = nil, nil
end
local function startDragByTouch()
print("start by drag")
cancelDragTimer()
item:removeEventListener( "touch", touch )
listener( item, touchevent )
item, touchevent = nil, nil
end
touch = function( event )
touchevent = event
if (event.phase == "began") then
display.currentStage:setFocus( event.target, event.id )
event.target.hasFocus = true
if (dragtime) then
dragtimer = timer.performWithDelay( dragtime, startDragByHold, 1 )
end
return true
elseif (event.target.hasFocus) then
if (event.phase == "moved") then
if (lengthOf( event.xStart, event.yStart, event.x, event.y ) > touchthreshold) then
cancelDragTimer()
if (angle and radius and isWithinRadius(event)) then
startDragByTouch()
else
scrollview:takeFocus(event)
return false
end
end
else
display.currentStage:setFocus( event.target, nil )
event.target.hasFocus = nil
end
return true
end
return false
end
item:addEventListener( "touch", touch )
end
return scrollview
end
-- attach drag-item scrollview to widget library
require("dragitemscrollview")
-- load widget library
local widget = require("widget")
-- create drag-item scrollview
local c = widget.newDragItemsScrollView{
backgroundColor = {1,0,0},
left=100,
top=100,
width=500,
height=800
}
-- create item to add to the scroll view (this will be dragged off the scrollview)
local circle = display.newCircle( 0, 0, 50 )
-- create a listener to handle drag-item events
local function listen( item, touchevent )
display.currentStage:insert( item )
item.x, item.y = touchevent.x, touchevent.y
local function touch(e)
if (e.phase == "began") then
display.currentStage:setFocus( e.target, e.id )
e.target.hasFocus = true
return true
elseif (e.target.hasFocus) then
e.target.x, e.target.y = e.x, e.y
if (e.phase == "moved") then
else
display.currentStage:setFocus( e.target, nil )
e.target.hasFocus = nil
end
return true
end
return false
end
item.hasFocus = true
display.currentStage:setFocus( item, touchevent.id )
item:addEventListener( "touch", touch )
end
-- add the drag-item to the scrollview
--[[
Params:
item: Item to add to the scrollview
listener: Listener function to call when a drag-off is detected
Dragtime: Milliseconds that a hold will begin a drag-off
Angle: Angle at which a touch-motion will begin a drag-off event
Radius: Radius around the angle within which the drag-off will begin, outside this will not
Touch-threshold: Distance a touch must travel to begin a drag-off (default is .1 of screen width)
Description:
This example will cause the white circle to be dragged off the scrollview only if the
touch begins and does not move further than the touch-threshold within 450 milliseconds
OR if the touch moves further than .1 of the screen width within 450 millisecond
BUT ONLY if the touch moves within 90 degrees of immediately east (right) of the initial touch.
The Dragtime determines how long a touch-and-hold will cause a drag to fire. Leave nil to
have only touch with distance begin a drag-off.
Angle and Radius define a range of direction which will fire a drag-off event. Outside of that
will result in the scrollview being scrolled. Leave nil to have only touch-and-hold to fire a
drag-off event.
The Touch-threshold can be used to define the distance that a touch-and-move will fire a
drag-off event. The default is .1 of the screen width.
]]--
c:add( circle, listen, 450, 90, 90 )
-- position the drag item in the scrollview
circle.x, circle.y = c.width/2, c.height/5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment