Dragging and Dropping Elements
Is there anyway to create Draggable and Droppable elements? Similar to the jQuery ones (http://jqueryui.com/demos/droppable/)?
If not can you point me towards using jQuery with Titanium?
9 Answers
-
Based on James' findings (the event not being able to properly set it's own .x and .y properties within it's "touchmove" handler), I came up with a long winded (but working) solution.
The basic idea is to create two objects - one to assign the touchmove event to, and the other to re-position. I also found that getTop() and getLeft() seem to get reset whenever the touchmove event fires, so I'm using separate vars to save their correct values (circleX and circleY) to remember the last position. Finally I move the event circle on top of the one that I actually moved, and prepare for the next press event :
var win = Titanium.UI.currentWindow; var circleSize = 100; var circleX = 145; var circleY = 0; var circle = Titanium.UI.createView({ height:circleSize, width:circleSize, anchorPoint:{x:(circleSize/2),y:(circleSize/2)}, borderRadius:(circleSize/2), backgroundColor:'#336699', opacity:0.3, top:10 }); var circle2 = Titanium.UI.createView({ height:circleSize, width:circleSize, anchorPoint:{x:(circleSize/2),y:(circleSize/2)}, borderRadius:(circleSize/2), backgroundColor:'#FF0000', top:10 }); var label = Titanium.UI.createLabel({ text:'Click circle repeatedly to animate or drag the circle', bottom:100, color:'#555', font:{fontSize:12,fontFamily:'Helvetica Neue'}, textAlign:'center', height:'auto', width:'auto' }); circle2.addEventListener('touchmove', function(e) { circle.setTop(e.y + circleY - (circleSize/2)); circle.setLeft(e.x + circleX - (circleSize/2)); }); circle2.addEventListener('touchend', function(e) { circleY = circle.getTop(); circleX = circle.getLeft(); circle2.setTop(circle.getTop()); circle2.setLeft(circle.getLeft()); }); win.add(circle); win.add(circle2); win.add(label);
Hope this helps someone =)
-
What is setLeft?
normally you would do
label.left = e.x;
the problem you are describing with the jumpings makes sense, you will need to detect the position of the touchstart inside the element and relatively on it's left/top position and substract it to set the left/top property
if you touch the label in the center and then use this position to set left/top, is clear that the new position will be shifted with width/2, height/2
here is an idea on how you could use this
var offset={}; label.addEventListener('touchstart', function(e) { offset.x = e.x- label.left; offset.y = e.y-label.top }); label.addEventListener('touchmove', function(e) { label.left = e.x-offset.x; label.op = e.y-offset.y; }); label.addEventListener('touchend', function(e) { // maybe some cleaning routines here or droppable stuff });
this code is not tested :)
let me know -
This works well and smooth on my android Samsung Galaxy GT-I8730.
Has a slight delay when dragging but comparing with other solutions this one works on an acceptable level.
Didn't test it on iPhone, but on the emulator when dragging, the movement is a bit jumpy.
Can anyone test it on a real device to see if this is something to do with the emulator or if it is something related to the framework?var win = Titanium.UI.createWindow({ width:Titanium.UI.FILL, height:Titanium.UI.FILL, backgroundColor:'#888' }); var view1 = Titanium.UI.createView({ width:75, height:75, backgroundColor:'#CCC', top:5 , left:5 }); win.add(view1); var view2 = Titanium.UI.createView({ width:75, height:75, top:5 , left:5 }); win.add(view2); var offset = {}; view2.addEventListener('touchstart', function(e){ offset.x = e.x - view1.left; offset.y = e.y - view1.top; }); view2.addEventListener('touchmove', function(e){ view1.left = e.x - offset.x; view1.top = e.y - offset.y; }); view2.addEventListener('touchend', function(e){ view2.left = e.x - offset.x; view2.top = e.y - offset.y; }); win.open();
-
On the native side, you would use the ontouchmove event, as in this example from the Kitchen Sink. If you wanted to use jQuery, you would have to do it from inside a web view - you'll see one of the examples sets a web view URL to a local HTML file, which includes jQuery.
-
I still can't seem to get this to work. The example won't move what so ever, but if I change the listener to (below) it will move correctly, but as soon as you let go and try and click on it again it wont move. You have to click on where the element use to be to get it to move?? It also flashes some when you are moving it.
Any Ideas?
circle.addEventListener('touchmove', function(e) { var t = Ti.UI.create2DMatrix(); t.translate((label.top - e.x), (label.left - e.y)); // pass inline animation objects and get callback when done label.animate({transform:t}); });
-
why do you use a transform to move it and not it's left/top properties?
for a droppable zone you can simply check on touchend if the center of the moved element is inside the droppable zone.
let me know
-
Tamas -
Here is what is weird. If I do:
circle.addEventListener('touchmove', function(e) { circle.animate({top:e.y,left:e.x}); });
Doesn't work at all.
If I do:
circle.addEventListener('touchmove', function(e) { circle.setLeft(e.x); circle.setTop(e.y); });
This moves around, but it is all jumpy and crazy.. so I tried it with the Label on the screen to but again it is jumpy and moves all over the place when I drag it.
BUT! If I do this:
circle.addEventListener('touchmove', function(e) { label.setLeft(e.x); label.setTop(e.y); });
It moves basically prefect, it jumps up to where the circle is but after that it moves exactly where i drag to. So for some reason the e parameter must be getting messed up when you have the move listener on the same thing as you are moving??
-
Haha, I just noticed they had Setters for Top and Left so I used them ;).
That didn't seem to fix the problem either.. It seems like when I click and start dragging the element ends up behind the cursor?? I'm not sure if this is a problem with my window and it is passing a different set of coordinates than what the element is in? (The element is just on the window.. So, I'm not sure how exactly this would matter)
-
It seems as if the 'e' parameter is returning an x,y coord. relative to the object you clicked on rather than its parent. So if you click on the top left of the element, you get 0,0 (regardless of its location within the parent)
By moving the event to its parent, that makes the problem seem less difficult, but the x,y coords. still seem rather radical.. and the element moves slowly.
Is this an intended feature? Seems rather silly to give you x,y coords based on itself? You can easily get those from the Parent coords (Parent.left - Current.left)..