Need Scrolling List of Objects I Can Grab & Drag

I have a scrolling list of display objects using the scrollView widget. I’d like to be able to grab one of the objects and drag it up onto the middle of the screen.

(Technically, I don’t want to remove that object from the scrolling list – I’ll just create a dupe of it and that one will be dragged so the original stays in the list.)

I have each object in the list looking for a touch event. When I see a vertical drag in that listener I can spawn a duplicate of that object.

The problem is that to get that vertical drag info (event.y < event.yStart) I need to return true from that listener.

But if I return true, then you can only scroll the list if you’re touching the background. Touching any of the objects and swiping to the side does nothing.

Is there a better way to handle what I’m trying to do? I’m hoping to be able to use the scrollView so I don’t have to code this whole piece from scratch.

 Jay

scrollytackbar.png

I’ve not tried this myself, but I believe the way to do this is to take the focus in the began phase and look for your gesture - in your case moving vertically. If you detect a horizontal move, you can pass the focus back to the scroll view with the takeFocus() function:

http://docs.coronalabs.com/daily/api/type/ScrollViewWidget/takeFocus.html

The historical problem was that returning true from the touch event would prevent passing touch events to the scrollview underneath, yet returning false would lose the ability to detect touch events at all. ‘takeFocus()’ allows you to setFocus on your list’s item and pass it back to the scrollview if you need to.

Oh, horacebury, you rock! (Which everybody knew anyway.)

While my first attempts with that haven’t completely solved my problems, I think I’m on the right track, at least.

Maybe. :slight_smile:

 Jay

Try this:

-- scroll and drag item demo local widget = require( "widget" ) function lengthOf( a, b ) &nbsp; &nbsp; local width, height = b.x-a.x, b.y-a.y &nbsp; &nbsp; return (width\*width + height\*height)^0.5 end stage = display.getCurrentStage() -- Create a ScrollView local scrollView = widget.newScrollView { &nbsp; &nbsp; top = 0, &nbsp; &nbsp; left = 0, &nbsp; &nbsp; width = display.contentWidth, &nbsp; &nbsp; height = display.contentHeight/2, &nbsp; &nbsp; scrollWidth = display.contentWidth\*5, &nbsp; &nbsp; scrollHeight = display.contentHeight, &nbsp; &nbsp; verticalScrollDisable = true, } local function dragItem(e) &nbsp;&nbsp;&nbsp;&nbsp;if (e.phase == "began") then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stage:setFocus( e.target ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.target.hasFocus = true &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true &nbsp;&nbsp;&nbsp;&nbsp;elseif (e.target.hasFocus) then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (e.phase == "moved") then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local start = {x=e.xStart,y=e.yStart} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (lengthOf(start,e) \> 10) then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (math.abs(e.y-e.yStart) \> math.abs(e.x-e.xStart)) then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-- vertical drag &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local dupe = e.target:duplicate(e) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-- horizontal drag &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;scrollView:takeFocus(e) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stage:setFocus(nil) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.target.hasFocus = false &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;return false end local function duplicate( self, e ) &nbsp;&nbsp;&nbsp;&nbsp;local grp = display.newGroup() &nbsp;&nbsp;&nbsp;&nbsp;grp.x, grp.y = e.x, e.y &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;local circle = display.newCircle( grp, 0, 0, 75 ) &nbsp;&nbsp;&nbsp;&nbsp;circle:setFillColor(255,0,0) &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;local txt = display.newText( grp, self.txt.text, 0, 0, native.systemFont, 52 ) &nbsp;&nbsp;&nbsp;&nbsp;txt.x, txt.y = 0, 0 &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;function grp:touch(e) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (e.phase == "began") then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.target.hasFocus = true &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stage:setFocus(e.target) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elseif (e.target.hasFocus) then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (e.phase == "moved") then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.target.x, e.target.y = e.x, e.y &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.target.x, e.target.y = e.x, e.y &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stage:setFocus(nil) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.target.hasFocus = false &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;grp:addEventListener("touch",grp) &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;stage:setFocus(grp) &nbsp;&nbsp;&nbsp;&nbsp;grp.hasFocus = true &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;self.hasFocus = false end for i=1, 10 do &nbsp;&nbsp;&nbsp;&nbsp;local grp = display.newGroup() &nbsp;&nbsp;&nbsp;&nbsp;grp.x, grp.y = i\*200, display.contentCenterY/2 &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;grp.duplicate = duplicate &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;local circle = display.newCircle( grp, 0, 0, 75 ) &nbsp;&nbsp;&nbsp;&nbsp;circle:setFillColor(255,0,0) &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;grp.txt = display.newText( grp, i, 0, 0, native.systemFont, 52 ) &nbsp;&nbsp;&nbsp;&nbsp;grp.txt.x, grp.txt.y = 0, 0 &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;scrollView:insert( grp ) &nbsp;&nbsp;&nbsp;&nbsp;grp:addEventListener("touch",dragItem) end

https://dl.dropboxusercontent.com/u/10254959/Help/ScrollListDragItem/main.lua

Nice! I had to change a setFocus(nil) in there to stage:setFocus(nil) to stop an error, but that’s pretty much what I need! Thank you!

 Jay

I’ve not tried this myself, but I believe the way to do this is to take the focus in the began phase and look for your gesture - in your case moving vertically. If you detect a horizontal move, you can pass the focus back to the scroll view with the takeFocus() function:

http://docs.coronalabs.com/daily/api/type/ScrollViewWidget/takeFocus.html

The historical problem was that returning true from the touch event would prevent passing touch events to the scrollview underneath, yet returning false would lose the ability to detect touch events at all. ‘takeFocus()’ allows you to setFocus on your list’s item and pass it back to the scrollview if you need to.

Oh, horacebury, you rock! (Which everybody knew anyway.)

While my first attempts with that haven’t completely solved my problems, I think I’m on the right track, at least.

Maybe. :slight_smile:

 Jay

Try this:

-- scroll and drag item demo local widget = require( "widget" ) function lengthOf( a, b ) &nbsp; &nbsp; local width, height = b.x-a.x, b.y-a.y &nbsp; &nbsp; return (width\*width + height\*height)^0.5 end stage = display.getCurrentStage() -- Create a ScrollView local scrollView = widget.newScrollView { &nbsp; &nbsp; top = 0, &nbsp; &nbsp; left = 0, &nbsp; &nbsp; width = display.contentWidth, &nbsp; &nbsp; height = display.contentHeight/2, &nbsp; &nbsp; scrollWidth = display.contentWidth\*5, &nbsp; &nbsp; scrollHeight = display.contentHeight, &nbsp; &nbsp; verticalScrollDisable = true, } local function dragItem(e) &nbsp;&nbsp;&nbsp;&nbsp;if (e.phase == "began") then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stage:setFocus( e.target ) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.target.hasFocus = true &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true &nbsp;&nbsp;&nbsp;&nbsp;elseif (e.target.hasFocus) then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (e.phase == "moved") then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local start = {x=e.xStart,y=e.yStart} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (lengthOf(start,e) \> 10) then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (math.abs(e.y-e.yStart) \> math.abs(e.x-e.xStart)) then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-- vertical drag &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local dupe = e.target:duplicate(e) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-- horizontal drag &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;scrollView:takeFocus(e) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stage:setFocus(nil) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.target.hasFocus = false &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;return false end local function duplicate( self, e ) &nbsp;&nbsp;&nbsp;&nbsp;local grp = display.newGroup() &nbsp;&nbsp;&nbsp;&nbsp;grp.x, grp.y = e.x, e.y &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;local circle = display.newCircle( grp, 0, 0, 75 ) &nbsp;&nbsp;&nbsp;&nbsp;circle:setFillColor(255,0,0) &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;local txt = display.newText( grp, self.txt.text, 0, 0, native.systemFont, 52 ) &nbsp;&nbsp;&nbsp;&nbsp;txt.x, txt.y = 0, 0 &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;function grp:touch(e) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (e.phase == "began") then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.target.hasFocus = true &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stage:setFocus(e.target) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elseif (e.target.hasFocus) then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (e.phase == "moved") then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.target.x, e.target.y = e.x, e.y &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.target.x, e.target.y = e.x, e.y &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stage:setFocus(nil) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.target.hasFocus = false &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;&nbsp;&nbsp;grp:addEventListener("touch",grp) &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;stage:setFocus(grp) &nbsp;&nbsp;&nbsp;&nbsp;grp.hasFocus = true &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;self.hasFocus = false end for i=1, 10 do &nbsp;&nbsp;&nbsp;&nbsp;local grp = display.newGroup() &nbsp;&nbsp;&nbsp;&nbsp;grp.x, grp.y = i\*200, display.contentCenterY/2 &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;grp.duplicate = duplicate &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;local circle = display.newCircle( grp, 0, 0, 75 ) &nbsp;&nbsp;&nbsp;&nbsp;circle:setFillColor(255,0,0) &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;grp.txt = display.newText( grp, i, 0, 0, native.systemFont, 52 ) &nbsp;&nbsp;&nbsp;&nbsp;grp.txt.x, grp.txt.y = 0, 0 &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;scrollView:insert( grp ) &nbsp;&nbsp;&nbsp;&nbsp;grp:addEventListener("touch",dragItem) end

https://dl.dropboxusercontent.com/u/10254959/Help/ScrollListDragItem/main.lua

Nice! I had to change a setFocus(nil) in there to stage:setFocus(nil) to stop an error, but that’s pretty much what I need! Thank you!

 Jay

that’s what I try to do for 3 days thank you very much !!!

that’s what I try to do for 3 days thank you very much !!!