Titanium Community Questions & Answer Archive

We felt that 6+ years of knowledge should not die so this is the Titanium Community Questions & Answer Archive

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?

— asked June 10th 2010 by James Armstead
  • draggable
  • droppable
  • jquery
  • mobile
0 Comments

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 =)

    — answered July 8th 2010 by Charles Gallant
    permalink
    1 Comment
    • This solution works but causes issues with click events since you have another object over it.
      After loosing much time on this and trying to hack my way around drag lags UI issues, I found this module that does the trick really nicely !! You also get pinch resize and rotation too…

      https://github.com/pec1985/TiDraggable

      Thanks Pedro !

      — commented January 20th 2014 by Christian Ribe
  • 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

    — answered June 11th 2010 by Dan Tamas
    permalink
    2 Comments
    • setLeft() is actually in the reference I have added to add autocomplete for Titanium.. I didn't realize they had added extra functions in it. Silly.

      — commented June 11th 2010 by James Armstead
    • i have tested the above code wen i drag the image its nt moving smoothly……
      pls help

      — commented November 21st 2012 by thaha hussain
  • 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();
    
    — answered September 8th 2013 by Luis Ferreira
    permalink
    1 Comment
    • what's the reason of delay please

      — commented February 23rd 2015 by Ahmed hamdy
  • 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.

    — answered June 10th 2010 by Kevin Whinnery
    permalink
    1 Comment
    • Interesting, I got the demo and got it loading up with the circle.. but the dragging part wont work for some reason? I can see in the trace that it is telling it to animate, but it doesn't move.

      — commented June 10th 2010 by James Armstead
  • 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});
    });
    
    — answered June 11th 2010 by James Armstead
    permalink
    0 Comments
  • 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

    — answered June 11th 2010 by Dan Tamas
    permalink
    0 Comments
  • 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??

    — answered June 11th 2010 by James Armstead
    permalink
    0 Comments
  • 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)

    — answered June 11th 2010 by James Armstead
    permalink
    1 Comment
    • I also just tested this on the device and it results are the same, so it can't be an issue with the emulator either.

      — commented June 11th 2010 by James Armstead
  • 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)..

    — answered June 11th 2010 by James Armstead
    permalink
    2 Comments
    • I'll give it a try myself :) and let you know

      — commented June 11th 2010 by Dan Tamas
    • Yea, I am really stumped on this one.. I can get it to drag along but it just doesn't keep up.. I really don't know if it is just the translation between the Titanium API to Android or if it just isn't working the way I think it should..

      Thanks for the help!!

      — commented June 12th 2010 by James Armstead
The ownership of individual contributions to this community generated content is retained by the authors of their contributions.
All trademarks remain the property of the respective owner.