Moving Views In Android – Part 3, Drop Zones

DragViewV2 at startI have come to the end of my work on drag-drop in Android. I now understand how views can be placed on the screen and moved by touching them. I also worked out how you can have different drop behavior for different areas of the screen. In my example, I called those areas DropZones. As you drag views around the screen, the drop zones light up to indicate that they are places where you can drop objects.

The figures  show what the app looks like at various points. Figure 1 is what it looks like when it launches. There are two red drop zones and one orange drop zone. There are two images initially visible. Figure 2 shows the menu where you can add other objects and enable and disable the orange drop zone. The other two show the background color changes in the drop zones as you move over them. Green means the drop will be accepted. White means it will not.

DragViewV2 menu

Figures 2-4

How It Works

The classes in this app are derived from the Android Launcher application. In an earlier note (see “Moving Views In Android – Part 2“), I had written up how the Android Launcher app supports moveable views using the touch interface. The Launcher object model includes objects like DragLayer, DragSource, DragController, and DropTarget. The one object I did not explore fully was the DropTarget. That’s what this note (Part 3) is about.

Here’s how DropTargets figure into the Android Launcher. In the Launcher, when you start dragging an icon, check out what happens at the bottom of the screen. You should see that a Trash icon appears. If you drag an icon over that icon, you will see a change in the color of the view being dragged. The red color gives you a good indication that something will happen if you drop the icon there. Since it is a trash icon, you know that it means the icon being dragged will be removed from the workspace. In code, what’s going on is that the Trash view implements the DropTarget interface.

The DropTarget interface defines the following methods:

 boolean acceptDrop (DragSource source, int x, int y, int xOffset,
             int yOffset,DragView dragView, Object dragInfo);
  Rect estimateDropLocation (DragSource source, int x, int y, int xOffset,
             int yOffset,DragView dragView, Object dragInfo, Rect recycle);
  void onDragEnter (DragSource source, int x, int y, int xOffset,
             int yOffset,DragView dragView, Object dragInfo);
  void onDragOver (DragSource source, int x, int y, int xOffset,
             int yOffset,DragView dragView, Object dragInfo);
  void onDragExit (DragSource source, int x, int y, int xOffset,
             int yOffset,DragView dragView, Object dragInfo);
  void onDrop (DragSource source, int x, int y, int xOffset,
             int yOffset,DragView dragView, Object dragInfo);

acceptDrop is there so the drop target has a way to tell the DragController that it is willing to accept a dropped object. The other methods are there so the drop target knows what’s going on during the move of the object. Each time you enter the area defined by the drop target view, onDragEnter is called. Each time you leave, onDragExit is called. That makes those the perfect spot to provide the user with feedback by highlighting the view or the drop target itself. In the Launcher, the view turns red when over a drop target. In my example, the background color changes.

In my example, I added a new class, DropZone, to implement the interface. I set up onDragEnter and onDragExit to make changes in the background color so the user gets a sense of where the dragged object will land. As you run the app, be sure to note the difference between the two red areas on the screen and the orange area. The orange drop zone is set up initially so that it will not accept drops. Try dropping something there and you will see that the dragged object returns to its starting location. Then try again, after using the menu to enable the orange drop zone. Note that the enter color becomes green and that you can drop something there.

Source Code

The source code for this demo application is available in two places:  (1) download from Wglxy.com. (2) download from Google Docs.  If you find that the app does not build in Eclipse, be sure to do a clean build by using the “Clean” item on the Project menu.

This work was done on a MacBook running Eclipse Galileo and Android 2.2.

About these ads

About Bill Lahti

Bill Lahti is a software engineer building mobile applications and knowledge management solutions. Two of his interests are writing for this blog and building Android apps, with strategy games being an area of particular interest.
This entry was posted in Android and tagged , , , . Bookmark the permalink.

89 Responses to Moving Views In Android – Part 3, Drop Zones

  1. Joe says:

    Thanks for the tutorials. Yours is the best explanation I’ve found so far for implementing drag and drop. Its a shame Android/Google hasn’t made this easier though!

  2. This looks really cool! I want to use something like this in a game im making. I hope to be able to drag components from a derivitive of a listview and then drop them onto different grid locations in a different view object. Do you think this would be possible?

    Think of the app in landscape mode, with the left 20% showing a list of items the player can install into their ship or character. The right 80% shows a layout of the ship or character and a grid of possible slots you can install components.

    • blahti says:

      I think that’s possible. For it to work, you will need to have the list view and the grid view both be child views under the same DragLayer. It sounds like your two views each have a layout of their own before you get down to the level of the view that actually moves around on the screen. My example here shows only simple views nested inside of the top level DragLayer.

      I did try to have the DropSpot views in this example themselves be draggable, but ran into a problem at the moment of drop. The drop code, as written, assumes that the parent of the view being dragged is the DragLayer. Check the layout xml files for this example and you will see that the parent of a DropZone is another layout, a RelativeLayout. So when it comes time to accept the drop, an error was reported about being unable to change the parent of a view. For this note, I chose to leave that problem unsolved. For what you want to do, I think you’d have to address it. Probably, the thing to do is create a new view with content derived from the view (or its model) being dragged. Attach the new view to your right hand side grid layout and then make the one on the left vanish. The view won’t literally move from one view to another, but that’s what it will look like to the user.

      • amadamala says:

        Thanks for great series of articles. I think I’m dealing with the problem you mentioned in the above comment.
        I’m getting the following error message.
        java.lang.IllegalArgumentException: Given view not a child of com.blahti.example.drag2.DragLayer@44743700
        at android.view.ViewGroup.updateViewLayout(ViewGroup.java:1876)
        at com.blahti.example.drag2.DropSpot.onDrop(DropSpot.java:223)
        at com.blahti.example.drag2.DragController.drop(DragController.java:446)
        at com.blahti.example.drag2.DragController.onTouchEvent(DragController.java:424)
        at com.blahti.example.drag2.DragLayer.onTouchEvent(DragLayer.java:69)
        at android.view.View.dispatchTouchEvent(View.java:3766)

        Do you have example code which I can follow to resolve this problem.

        Thanks in advance.

      • blahti says:

        Yes, that’s the error I have seen. Sorry, I do not have an example with a solution.

        In my Part 2 note, I made the following suggestions:
        (1) move everything under one ViewGroup so all the movable views have the same parent view; (2) arrange to change the parent view of the view being moved when that view is dropped. But today I think I’d try what I suggested above: (3) in the view that is accepting the drop, make a copy of the view being dragged. Attach the copy as a child of that view. Go back to the original view and remove it from its parent.

        The problem is that in onDrop of DropSpot, it is missing information. It assumes that the parent of the view is the DragLayer itself. It does not know the parent of the original view. One way to address this would be to save the parent of the movable view at the time it is created. It’s that or you have to save the information by extending DragLayer so it knows the parent views of all draggable views within it. Once you have the parent view, you can remove the old view after you make the copy.

      • blahti says:

        My latest blog post (Drag-Drop for an Android GridView) might help. It does not solve the problem of changing the parent of a view, but it does show how to get the drawable of an ImageView shift from one position to another.

      • Steve says:

        Thanks blahti for providing this awesome tutorial :)

        The java.lang.IllegalArgumentException: Given view not a child of com.blahti.example.drag2.DragLayer@44743700, can be easily fixed adding the following 3 lines of code to the onDrop method of DropSpot:

        ViewGroup parent = (ViewGroup)v.getParent();

        parent.removeView(v);

        mDragLayer.addView(v);

        Instead of copying the view you can just change it´s parent, and voilá problem solved :)

        By the way this is the only example where you can drag and drop freely where you want right? I mean i didn´t tested the new dragdrop framework you made but it seems they only work for gridviews?

      • blahti says:

        Thanks for the fix. A lot of people have asked about that.

        Both this example and the one in Part 2 make use of AbsoluteLayout. So objects can be dropped wherever you want. In the newer examples, I have been trying to work with other views to make it easier for the code to be used with the layouts people are likely to be using in their apps.

      • Steve says:

        Hum okay but since Absolute Layout is deprecated, probably we should use something else like Frame Layout? I mean what does the official drag and drop framework from API 11 uses?

        Thanks

  3. Dave says:

    Hi Bill,

    I’ve used your tutorial to create a configurable view in my app. Thanks so much for your work. I’m struggling to find a way to then save the user layout so they have it again the next time they use the app.

    I’d like to be able to parse the xml into a file and then back again, is this possible?

    • blahti says:

      For the apps I am working on, I am considering a different approach. Get the current state of all the views on the screen, and save their types, sizes, and positions in a database. Then, when the app restarts, recreate all of the views and position them as they last were.

      I have not done that yet so it’s just an idea. Your xml idea sounds interesting too. I’d like to hear if that works.

  4. arjan says:

    Thanks for the clear and instructive tutorial, like one mentioned before.. best explanation so far.

    as always my mind goes wandering ahead..wanting more :)

    as i am still a starter when it comes to developing for android i am still trying to find out what is possible and what not.

    in your example the dropzones are squares (filled views).. but what if i like the dropzone to be a circle?

    I can draw the circle in the view, but the dropzone would still “light up/activate” when hovering the corner of the view and not touching the circle.

    is it possible to actually have the circle itself (without the corners of the view) as a dropzone, or must it be attached to the view.. i.e. its like that and suck it up..

    cheers
    arjan

    • blahti says:

      At one level, the answer is no. Views are rectangular so a DropSpot cannot be a circle. However, any class that implements the DropTarget interface can do whatever it needs to in methods like onDropEnter.

      In my example, I highlight the drop spot.

      public void onDragEnter(DragSource source, int x, int y,
      int xOffset, int yOffset,
      DragView dragView, Object dragInfo)
      {
      int bg = isEnabled () ? R.color.drop_target_enabled
      : R.color.drop_target_disabled;
      setBackgroundResource (bg);
      }

      Since you have the x-y coordinates, you could use them and not turn on highlighting until the point is inside the circle. The same logic would apply in the acceptDrop method. Do not accept a drop at a point unless it is inside the circle.

      So I think you can get the behavior you want.

  5. Yati says:

    Hi,i am unable to download the project..Can you please mail me..

  6. emmy says:

    Great tutorial.Sir ur uploaded zip file has corrupted,so please upload a fresh copy it if u can.

    • blahti says:

      Try the new link: https://docs.google.com/leaf?id=0B0wYSnCBkoR6ZDMxMTBkNDItODNiOC00MDUyLWIyZDMtMTk2NzkxOTAzZDQz&hl=en_US

      I could not find anything wrong with the old zip file. Were you able to get the zip file and its contents and then it would not build in Eclipse? If that’s the case, try doing a clean build from the Eclipse Project menu.

      • emmy says:

        No sir, i m not able to get zip files it message me “unknown format or damaged “.same is the case with new link.

        By the way sir i want to know that how to move an image/ rectangle on the screen horizontally or vertically (regular motion) not irregular motion.which i want to further use in “8 number puzzle game”.
        so please sir guide me. Thanks in advance.

      • blahti says:

        Here’s a way that you could do vertical or horizontal motion.

        Notice that in the DragController onTouchEvent method, you have access to the x and y coordinates of where the drag pointer is right now. Also note that it is the place that moves the DragView object that you see moving on the screen. I would consider making changes there and rather than making the call to the move method with both the x and y coordinates, make the call with only the x or only the y. Something like: “mDragView.move (ev.getRawX (), constantY)”. What “constantY” is depends on your game and where the drag began.

        How you determine whether you are moving vertically or horizontally when a drag operation begins is something you’d have to figure out too. Does the user have to indicate a preference somehow? Or do you check the event x-y values after the object moves enough and see if it is moving more in the x direction or the y direction?

        onTouchEvent also calls drop when the dragging is over. You’d want to change it to go along with the changes you make during the drag.

  7. Jonathan says:

    Is it possible to have the items move without using the onLongClick? I noticed the onLongClick method is boolean while onClick is a void. I’ll poke around but I was just wondering. It would be nice to not have to tap, hold, & wait.

    • blahti says:

      Take a look at the startDrag method in the activity. It takes the DragController and starts a drag operation within the DragLayer. Any way you can think of to get that operation started is fine: long click, regular click.

      If you don’t want drag-drop in response to a user touching the screen, but instead want to move views based on some other control on the screen, you’d have to do something different. I’d suggest studying the code that moves the DragView and the code that repositions the view when the drag ends. That would get you started with some useful code sequences for movement in general.

      The reason onLongClick returns a boolean is to indicate that the event has been handled. I think that means that other listeners on that event do not get called. It seems that onClick is also triggered and there has to be a way to keep those handlers from running. See http://stackoverflow.com/questions/742171/longclick-event-also-triggers-click-event

  8. DroidFan says:

    Hi, I’ve made an app that adds views dynamically using your method and it works fine. Thank you!
    But I want to make my imageViews rotate (when choosing rotate option if the user moves his finger up/down the image rotates counter-clockwise/clockwise. Can you please help me achieve this? I can’t find where and how to modify your project…

    Thanks again for your great work!

    • blahti says:

      This example is based on the code for Android Launcher. That code included some animation effects in the DragView class. I removed what they had to simplify the example.

      I have not done anything with animations yet so I do not have much help to offer. I would suggest getting the original source and studying their DragView and SymmetricalLinearTween classes. See http://stackoverflow.com/questions/4989425/getting-launcher2-source-code . The package name for the Launcher is com.android.launcher2.

  9. Pingback: Moving Views In Android – Part 2, Drag and Drop « More Is Not Always Better

  10. Ragupathy M.M says:

    Hi, very useful tutorial.

    im developed this one with help your tutorial but i need to exchange the views.
    if i drop the view to another view means it exchange that views. like android HTC home screen. so help me.. how to do this. im new one for android. so help me…

    • blahti says:

      See my comment from June 7 above. Is that close to what you are asking?
      If that’s the question, you need to either move the view or make a copy of the view and add it to the new spot and then remove the old. I almost think making a copy is going to be easier. From the user’s point of view, it will look the same.

  11. rori says:

    That´s is really great!
    Could you please tell me about using a intent to call an activity, when target got dropped in the right zone, is it possible?
    Thanx a lot!

    • blahti says:

      Sorry for the slow response. I lost track of your comment in the long list of questions.
      Two places you might start the activity from: (1) onDropCompleted in DragLayer; (2) onDrop in DragLayer. If you do the second one, you’d want to wait until after the view has been repositioned. Those two methods are implementations of methods in the two different interfaces: DragSource and DropTarget. If you have done your own implementations of those interfaces, you should choose the method that does the most to keep the separation between the code that implements dragging and dropping and the code that handles the event of something being dropped. To me, it seems like onDropCompleted is most like an event handler.

      As for starting the activity, it would look something like: “startActivity (new Intent(getApplicationContext(), YourNextActivty.class));”

  12. NSD says:

    Hi Blahti,
    This is nice tutorial. I want to ask you something. Have you worked on any game development tutorials, like checker or chess game.? If so let me know how can we design a checker/chess board, using android and how can we place the coins over it? Waiting for your early and prompt reply.

    Thanks & Regards,
    NSD.

    • blahti says:

      I am working on a game app, but have not done any articles or tutorials about games. I have used a GridView to do a game board. For the squares, I used a LevelListDrawable so I could easily change a square from empty to occupied by calling setImageLevel (level). I suggest starting with a single view whose drawable is defined in terms of a level list xml file and then building from there. See the page for LevelListDrawable for more information.

  13. NSD says:

    Hi Blahti,

    In this tutorial, the image is moving everywhere. can’t we restrict its position? Why we are using long click to highlight the image? Just by touch method we can’t highlight the image? If so can you please help me out.

    Thanks & Regards,
    NSD.

    • blahti says:

      Moving is handled in the onTouchEvent of DragController. It calls the move method of DragView. So if you want to restrict movement while the dragging is going on, you could change those methods. For instance, you could choose to ignore the x position and have the view move by tracking the y position. Another thing you could think about is where the DropTarget accepts the dropped object. Check onDrop in DragLayer. My demo takes the x-y coordinates and uses them, but you wouldn’t have to. The Android Launcher code looks for the cell closest to the x-y position and positions into that cell.

      Why long click? This demo was based on what the Android Launcher did. If you check your Android home screen, click starts the app at the position. Long click initiates a drag. If it makes more sense in your app to let a click be the start of the drag, you could do so. See onClick and onLongClick in the DragActivityV2 class.

  14. NSD says:

    Hi Blahti,

    I have one doubt can we create a checker/chess board using XML ? If we can use XML , how to place the coins over it randomly but each player should have similar coins.? If we can use XML how can we highlight over the XML Board.? If we can use use XML , how can we move the coins horizontal , vertical and diagonal?

    I have on issue, I have “five different squares”, the property of each squares are different. Like “Plain Square”, where the coins placed over the plain square can move in horizontal and vertical; “Pattern Square”, where the coins placed over the pattern square can move in diagonal direction; “Image1 Square”, where we can have only one move in all directions; “Image2 Square”, where we can have only two move in all directions;”Image3 Square”, where we can have only three move in all directions. These are the five different squares, if you can solve this problem, that would be great help to me.

    Thanks & Regards,
    NSD.

    • blahti says:

      See my response to your earlier question. LevelListDrawable may get you what you want. You don’t have to views that move that way. By setting the image level of different squares, you can create the appearance of movement. That might be easier than actually moving views around.

  15. mayank_625 says:

    hi,
    man you have really done a great job. i want to use your source code can you please tell me what the changes i have to made, i m getting confused with that draglayer xml file , need your help, hope your kind response.and really thankful for your series of drag and drop tutorials.
    thank you

  16. mayank_625 says:

    now i can drag the image view but on drop it doesnt let me add on drag spor, pls help me if u can…..waiting for ur response

    • blahti says:

      I’m not sure what you are asking. Please provide a bit more information.

      • mayanksarda says:

        i am implementing your code in my application and i have also added all the dragged views in drag layer file, but when i drop the view at any layout it throws an exception saying that its not a child of that layout.!! i think its not allowing to add the view can you tell me what to do?…

      • blahti says:

        I do not have any code examples that work around that problem. I have made a few comments above about how I would think about it. See those and go back to my earlier article on Drag-Drop and read the comment (dated July 6). The suggestion I make above in the June 7 comment is what I’d try first.

  17. mayanksarda says:

    Oops, Sorry, I did not see any comments previously !, but Thanks again, I got your idea from that comment, i will try if the drop spot is not a child view and i had also put that view which i was willing to drag is in child view so i think the image view must be child only of a drag layer. Thanks for nice tutorial. I will try how to sort out this problem….!!!

  18. mayanksarda says:

    hi bill,
    Thanks a lot for your all the tutorials on drag and drop, they had been really useful for me, i just need a one solution. You are extending the absolute layout right?, but it does not let me set the the positions of image view manually, please give me suggestions on that because it doesnt let to add them in any other layout and you havent set any attribute for moving them anywhere in xml file, hope you have got something to say on that

    • blahti says:

      In the Part 3 tutorial, I have code that adds images dynamically. Click the menu key and you should an option to add an image. If you follow the code for that, you should find a code sample in DragLayer onDrop that adds an image to the layout. It looks like

      DragLayer.LayoutParams lp = new DragLayer.LayoutParams (w, h, left, top);
      this.updateViewLayout(v, lp);

      The code that handles adding a view looks very similar.
      Is that what you were asking?

      • mayanksarda says:

        yes, but i did it using MyAbsoulteLayout.LayoutParams , thanks very much again. I really want to suggest one thing if you can develop part-4, then, please show the also for positioning that draggable imageviews in anyway, as you want. That will be the most helpful thing in adapting your drag and drop tutorial series.

        Thanks,
        Mayank.

  19. mayanksarda says:

    Hi bill, This is mayank here again, i got only one little question again, can you tell me if i want to start drag on touch listener then what changes i should do? because implementing touch listener for dragging hangs the phone…So it will be really useful if you show any way to drag the view on touch listener rather than on long click….!!! Thanks…

    • blahti says:

      Dragging hangs the phone. Do you mean you get the message from Android about the activity not responding and then being given a choice to wait for force close the app?

      Usually, when I see this dialog box, I have accidentally started doing a long-running task in the UI thread. I’d suggest you look for that. Something to keep in mind is that all the Drag-Drop code in my demo programs run in the UI thread. Anything you do in DropTarget or DropSource methods should run quickly. They are just like the code sequences you put in onClick or onLongClick.

      My guess is that you have added code in one of the methods (onDrop, onDropCompleted, for instance) that takes too long to run. If that’s the case, you will want to move that work to background tasks. See my note on background tasks. If this sounds possible, you can verify my guess by taking your code sequence and add to some onClick method somewhere. If you get the same force close dialog, that would indicate that drag-drop is not not the issue.

      Of course, I am just guessing from your short question. It could be that you are trying this in a new version of Android or there is something going on in code you have put in place that has created a loop that indeed does not terminate. While working on a demo app, I found some new words of caution in the Android documentation about how tricky it is to get touch events handled correctly. Be sure to read the description of onInterceptTouchEvent in class ViewGroup. Perhaps you’ve encountered something new.

      • mayanksarda says:

        Hi, Actually I lately came to know that it does not give not responding dialog but it just gets hung, maybe it calling looper.prepare(), so there will be no ui control, but my question is why this is happening, it should work like same as onLongClick event.. and i came across with onInterceptTouch event first time in android. And i have changed your code in the DropSpot part not in any other files, I think it should work onTouch event too, but somehow its not working after the first drag and drop an item it hangs the screen and its related to thread again i think, can you give any suggestion on that…?

      • blahti says:

        The only thing I can think of is that there is something in the onLongClick sequence of method calls that is not happening when you start the drag with onClick. At the activity level, look inside onLongClick. You should see something like:


        if (!v.isInTouchMode()) {
        return false;
        }

        That check of isInTouchMode could be significant.
        So there is something about views so they know if they are in touch mode. I would not be surprised if there is something in the DragController class that changes its state just the right way because of long click. (Note: Remember that much of this code originates in the Android Launcher code. There are a few things in it I have assumed just works. I don’t know it perfectly.)

        You might try temporarily changing your app to wait for a long click to start the drag operation. If the first drag operation works fine and all the following ones do too, you would know that the problem was introduced with the change to starting with onClick. The only thing to do then is to go through the code carefully and see how the events flow through the DragLayer and DragController and look for the line(s) that depend on it starting with onLongClick.

  20. Pingback: Drag-Drop for an Android GridView « More Is Not Always Better

  21. Sam says:

    Thank you very much for this set of tutorials, they have been really helpful.

    Anyway, have you managed to configure the LayoutParams method in MyAbsoluteLayout? I’d like to set the position of my views via xml using something like android:layout_x=”50px”.

    Any idea?

    • blahti says:

      I added MyAbsoluteLayout by copying the deprecated AbsoluteLayout. If you change it back to AbsoluteLayout, I think the xml layout parameters will work.

      I should also point out that I did some more work on drag and drop that does not depend on AbsoluteLayout. See Drag Drop for a GridView. If AbsoluteLayout seems like it’s not a good idea for your work, it might give you a few ideas on how to use one of the supported ViewGroup classes.

  22. Gaurav says:

    Thanks Blhati for this awesome tutorial I followed your tutorial and was able to achieve the the drag but when i am droping the view its refrencing draglayer as its pearent but its current is absolute layout.Actually i am naive in android development please help me if you can with code so that i am able to update the view parent.I went through your code so that i can remove draglayer view and things like that but was not able to achieve the drop please help me i am stuck.

    Regards:
    Gaurav

    • blahti says:

      There are few comments on this post related to the problem of dragging a view from one view to another when a change in parent view is implied. Also read through the comments in Part2. I have outlined the steps needed for a solution.

      I also did some more work on drag and drop that does not depend on AbsoluteLayout. See Drag Drop for a GridView. It arranges to create a new view when the drop occurs. Information from the old view is copied to the new view. From the user’s point of view, it looks like the object moved, but moving the information is sufficient.

  23. ashish says:

    hi your tutorial is good and clear. but can you please mention how to save those as a single image to sd card

  24. Bugsvanni says:

    Hi blahti,

    I am new to android, and i am currently developing an app that would switch devices on/off remotely via wifi. Now i have perfected my app using a listview. now i was wondering at first how to make my app a more user-friendly app, which then i saw your example. my app goes like this, just add devices, set an image for the device and drag it over the screen which resembles your house’s floorplan. now my only problem is, if the user would like to change the drag-able picture or delete a view on the screen, would that be possible? my app has its own database. everything integrates with the database first before managing/updating views.

    • blahti says:

      Please take a look at what I wrote about Drag-Drop for a GridView. Its views are dragged to and from a GridView in that one. I wonder if you could use a grid laid on top of a background view that displays the floorplan. The user sees the floorplan and drags things onto it. The grid is fine enough to allow the dragged devices to placed with enough precision on the floorplan. If that works out, all you’d have to do is find a way to tie the drag and drop actions to code that updates the database to match what the user is doing. A Listener interface could work. You could define something like onDeviceMoved, which could be called in the DropTarget implementor and it would have whatever arguments you needed on the handler’s side of things so it could update the database to keep it consistent with what the user sees on the screen. In your DragSource implementor, you’d likely have to save some extra data so it would be available at the end when the drop occurs. I know this is a bit sketchy, but think about the number of times you define onClick or onSomething methods in your Activity classes. Those handlers translate between what the user sees on the screen and what you have to save in a database (or SharedPreferences). That’s what I’m suggesting for your consideration.

      • Bugsvanni says:

        Hello blahti,

        I was successful in creating my app with 70% of your source code(thank you for your wonderful tutorial). I can now add devices on the screen. now my only problem is, how can i save the layout so that the user doesnt have to put the devices on their designated location all over again?

        I have tried to save the X,Y coordinates of a view on the screen and saved it over the database. im just confused what method to use to set the position of the views at the start of the activity. I am definitely stuck with this problem.

        what im doing right now since i dont have the answer yet to my problem is, im trying to integrate my previous code to my New code to send UDP packets to my Wifi module everytime i click the the views. and that would trigger any devices connected to my wifi module on/off.

        i am really looking forward on a solution to my current problem in setting view’s position at the start of the activity. i rejected xml parsing solution since i dont like parsing foreign language data. thank you in advance.

      • blahti says:

        The GridView demo does not address the problem of restoring its state from a database. I don’t have a good example to share with you about how to do that, but I will look around for one. Until then, here are a few comments.

        What you should look for is an example of restoring information from a database and then updating a list view with items that correspond to what’s in the database. A GridView is a little different than a list view, but not much. They both have an adapter that does the work of creating views. If I am remembering correctly, a good solution would be something like: (1) in onCreate you create your GridView, initially empty; (2) in onResume you read your data in a background task; (3) when the task finishes, your code updates the GridView and fills it in, matching what’s in the database.

  25. blahti says:

    To anyone looking for an answer on how to start drag-drop from a single click rather than a long click see my recent post: Improved Drag-Drop for an Android GridView.

  26. Yoonyoul says:

    I want to say thank you since I made a simple android collage app based on your code. its name is collagephoto. it’s very simple app that I made.
    anyway thank you again and I hope someday I can help you either. :)

  27. Thanks Blhati for this awesome tutorial I followed your tutorial and it is working excellent. I am new in android .

    I have a different kind of requirement. Let me explain

    I have a dashboard layout in which i have some buttons. I have a tab at the top of the layout. There are two option in tab.

    let say first option is parent which calls the parent activity and second option is child which calls the child activity. Both Activities having different-different dashboard layout.

    Now what i want is to drag some buttons from parent activity and drop to child activity and you can say from parent activity’s dashboard to child activity’s dashboard.

    How can i do this ? Please explain

    • blahti says:

      I assume that you are keeping track of which buttons appear in the parent view and which buttons appear in the child view, meaning that when you click to the parent you see set A of buttons and set B, for the child. Given that, you’d need a way to drag buttons from the parent somewhere that indicates that they are to transfer to the other view. You might consider doing something like is done in the official Android launcher. When you initiate a drag there, a trash can icon appears at the bottom of the screen in case you want to remove the icon from the desktop. In your case, the new thing would be something that suggests that dragging there is really a transfer to the other view. See Drag-Drop for a GridView for a demo app that has a trash icon on the screen. Using this drag-drop framework, you’d have to implement the logic so that new drop target does the transfer but there are methods in the DropTarget interface that would meet that need. Finally, you’d want to have the new icon be invisible until the drag starts. That would not be too hard since it is simply changing the visibility of a view, for which there are several examples in my series of tutorials on moving views.
      To do this, be sure you have a good understanding of the series of messages that occur during a drag-drop operation. I think you will find the framework is general enough to meet your need.

  28. Ravishankar says:

    Hi Blahti,

    Great Post, Nice work and thanks for sharing it. Your code helped me almost to complete my app but unfortunately got stuck at the final touch.

    Let me first explain you what I am trying to develop.

    I used your code and modified the DragSpot by adding a background image. The background image is nothing but a upper case alphabet A and I have three ImageViews say Apple, Ball & Cat. These ImageViews are the child view of DragLayer

    I have modified the code in such a way that a simple touch on any on these ImageView will initiate the Drag sequence. Also, I modified the code logic to accept only the Apple ImageView as a valid Drop on the DropSpot and rest of the ImageView is an invalid drop and it will snapback those invalid ImageViews to their original position from where the Drag sequence has been started.

    So far everything worked fine and good. But, the problem is those three Imageviews (Apple, Ball and Cat) are stacked up with one over the other ImageViews in LIFO manner(Last In First Out) in the screen.

    I tried to align them, but I cant align them properly and had no control over their position and alignment.

    Then I tried to put those three ImageViews inside an RelativeLayout. Now, I got the proper alignment what I wished for. But when I drag and drop the Apple ImageView over the DropSpot, I get Runtime Exception as follows

    java.lang.IllegalArgumentException: Given view not a child of org.sample.programs.dragdrop.DragLayer@44efb640
    05-07 23:31:50.472: E/AndroidRuntime(280): at android.view.ViewGroup.updateViewLayout(ViewGroup.java:1876)
    05-07 23:31:50.472: E/AndroidRuntime(280): at org.sample.programs.dragdrop.DropSpot.onDrop(DropSpot.java:219)
    05-07 23:31:50.472: E/AndroidRuntime(280): at org.sample.programs.dragdrop.DragController.drop(DragController.java:450)
    05-07 23:31:50.472: E/AndroidRuntime(280): at org.sample.programs.dragdrop.DragController.onTouchEvent(DragController.java:428)
    05-07 23:31:50.472: E/AndroidRuntime(280): at org.sample.programs.dragdrop.DragLayer.onTouchEvent(DragLayer.java:69)

    I read all our readers comments and your replies for the same issue what I face. But, I could not find an solution or fix or work around for the problem.

    It would be a great help for me, if you or any of your reader share a working code or snippets on how to align ImageViews or to overcome this Runtime Exception.

    I would request you to post a part 4 for the same Drag and Drop series, which has a fix for the above mentioned problem.

    I tried all my best but could not find a solution. So, please help me.

  29. Ashish says:

    Mr Blahti, I have gridview of images, I want to implement drag and drop in gridview item, How to implement, In your example, there are filled images which extends ImageCell class , In my case, I have a array of bitmap which are showing in gridview and there are an drop zone, I want to implement drag and drop in gridview item.

    When ever i goes to modify your code according my need , It always give me ANR dialog(Fource close). Please help me,

    • blahti says:

      You have seen my GridView example, right? You mention ImageCell so I think you must have. Is there anything being reported in the Logcat window of DDMS?

      • Ashish says:

        Mr. Blahti, I have a array of images (Bitmap) which are displaying in a gridview. I want to drag a copy of Gridview items(an images) which are selected and drop in Gallery view to show in a form of gallery.

        but in [your example](http://blahti.wordpress.com/2011/10/03/drag-drop-for-android-gridview/) all gridview item works as DragTarget(First add images then apply drag and drop).

        In simply i am trying to say, How to implement the drag and drop on fullfiled gridview.

        Have a look [my view](http://i.imgur.com/AxiUm.jpg)

      • blahti says:

        Dragging between two regions on the screen only works if all of the views are within the same DragLayer. So the first thing you will have to do is have your DragLayer be the layout in which your grid of images and your drop zone (the region with the blue border) are defined. Then you have to arrange for your GridView to use something like the ImageCell objects in them. What’s important is that any touch events that they receive are relayed to the DragLayer’s DragController because that is the object that makes dragging and dropping work. If you look at my GridView demo, you will see how I got ImageCell objects into a grid. You should do something similar. Your ImageCell implements only the DragSource methods. Mine did both DragSource and DropTarget interfaces.

        In my GridView demo, the ImageCellAdapter is where the click and touch listeners are set up for ImageCell objects. That is in getView. Find the lines near “v.setOnTouchListener ((View.OnTouchListener) mContext);”. mContext there ends up being the Activity. So the way touch events get to the DragController is as follows: Touch event on the ImageCell go to the listener assigned (the Activity); code in the activity (in method startDrag) assumes it has a DragSource and tells its DragController to get things started; the DragController gets a DragView and allows you to move it around; if the controller sees that it is over a DropTarget, it sends the right messages. If your app is blowing up, I suggest running in the debugger and following the flow from the point of touch to the point where the DragController gets to start.

  30. kiemduong says:

    Hi Mr. Blahti,
    How about scaling and animation for dropping?

    • blahti says:

      Check class DragView. There are two constants there related to scaling. The original Android source code, on which this demo and the one before it (Part 2) are based, made the dragged image larger than the original It also had some animated effects for the dragged object. I removed the animation because I was trying to simplify the example to be about drag-and-drop only. You might want to go back and study the Launcher code in the Android source code to see how they did animation. It might have been pretty basic stuff, perhaps just a flickering effect while you are dragging. I don’t recall the details.

  31. android_learner says:

    Hi i am trying to use your drag and drop for arc menu https://github.com/daCapricorn/ArcMenu

    but when i place com.splashscreen.draglayer outside com.splashscreen.arcmenu in xml

    it’s giving error?

    basically trying to drop 10 icons to arc menu to customize them

    Thanks a lot for your help

    • blahti says:

      I don’t know much about that menu you are trying to use, but it does look interesting.
      What error message do you get? It might have to do with being a subclass of MyAbsoluteLayout, which is a deprecated class in Android.
      I did these examples so I could understand basic drag-drop and I chose to use absolute layout, in order to simplify things. That does not make it easy to adapt it for other uses. Take a look at my newer post on Gridviews. It works without relying on absolute layout. If you can follow what’s going on there, you can probably come up with a new kind of DragLayer that is compatible with the ArcMenu you want to use. Here is what you are looking to understand: (1) a standard view (GridView) works inside a DragLayer; (2) its child views have been modified to support the DragSource and DropTarget interface. Try to do the analagous thing for ArcMenu.

  32. android_learner says:

    Hi Mr. Blahti,

    I want to use scrollview with 10 icons instead of gridview and scrollview consists of some images which should be swapable with some icons in arc menu?

    Thanks for the help I am a beginner developer trying to understand java and android together.

  33. android_learner says:

    how to swap images on drop so that grid view image is swaped with the bottom image?

    Thanks for your help

    • blahti says:

      Look at the code in ImageCell where the new image is put into the cell. The method is onDrop. It calls setImageDrawable to do the work. Note that onDrop receives the DragSource where the image came from. For what you want, all you have to do is cast the object to ImageCell and then determine that it is the bottom image. Then get the drawable of both the source and the current cell before you overwrite either and then make two calls to setImageDrawable.

      • Preethy Borrawar says:

        Hi Blahti,

        Thanks so much for your help i go the swapping Could you please tell me how to make the grid icons draggable and bottom image to be droppable?

        Thanks

        On Wed, Nov 28, 2012 at 6:27 AM, More Is Not Always Better wrote:

        > ** > blahti commented: “Look at the code in ImageCell where the new image is > put into the cell. The method is onDrop. It calls setImageDrawable to do > the work. Note that onDrop receives the DragSource where the image came > from. For what you want, all you have to do is cast the o” >

  34. Android Help says:

    Hello Sir , I have problem in the drag and drop. Actually i want drag an image from many images and put this image on a specific position and only that image can be set not another image could not be set and when we trying to set that position then print a message that this image cant’ be set try another
    Am try to understand your tutorial but can’t done. So plese tell me, or send me a code on my email, Please…..
    email: hemant.katariya26@gmail.com

  35. Balaji says:

    Hi Sir,
    It really great tutorial, thank you. I am trying to show dialog box after image view collision on DragSpot, I have multiple DragSpots on layout, depending on DragSpots ID, I need to show different dialog boxes.

    Can you please let me know where to I get the DragSpots ID.

    Here I am trying to get DragSpots ID in DragSpot class:

    public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
    DragView dragView, Object dragInfo)
    {
    toast (“onDragEnter”);
    int bg = isEnabled () ? R.color.drop_target_enabled : R.color.drop_target_disabled;

    // Toast.makeText(getContext(), “Target”, Toast.LENGTH_SHORT).show();
    setBackgroundResource (bg);
    }

    • blahti says:

      Sometimes I store extra information in the Tag for a View (see doc for getTag and setTag).
      The code could take the tag and then look up the associated dialog box. If you had a lot of those, creating a HashMap would help, as opposed to using a switch statement. I guess if you are looking at onDragEnter, you are looking for something that is temporary and that would stop showing when the touch went outside the bounds of the drag spot.

  36. Pingback: Drag-Drop for an Android GridView | More Is Not Always Better

  37. Archana says:

    Hi its a great tutorial which helped me in understanding drag and drop. can it be possible to drop into PopupWindow having listview.

    • blahti says:

      Yes. It should be possible. Take a look at the two more recent blog posts I did related to GridViews. The adapter object for the GridView returns DropTarget compatible objects in its getView method. A similar thing could be done for ListViews. If your work is for Honeycomb or later, you will probably want to use the new support for Drag and Drop that has been in Android since API 11. You might find it easier to set up the list of potential drop targets that way. My write up on that is here: Drag-Drop for GridView (V4).

  38. Wafa says:

    Hi,

    First, thank you for the useful tutorial. I want to ask you a question and hope answer me. In your code, if I wand spot 1 accept image 1 only to be dropped in but don’t accept image 2. also, spot 2 accept image 2 to be dropped in but don’t accept image 1, so when image 1 dropped into spot 2 it will return to its initial position. can I do that and if you have any idea about how can I do it please tell me.

    thanks alot.

    • blahti says:

      Look at the various places that react to an object being dropped and possibly the places where the drag starts. If you have extra conditions for whether a drop is accepted, you can add them there.

      • Wafa says:

        Thank you. I did that and it is done. But I faced new problem that I can’t solve it until now. I want to put three image views at the top (left, center, right) so I can drag an image to the correct drop zone at the bottom( three drop zones). but I can’t modify the code in away make the images ordered at the top (left, center, right) can help me?

        thanks alot.

      • blahti says:

        This article and the earlier one (Part 2) were done with the now obsolete layout AbsoluteLayout. At the time I started, I most wanted to understand drag-drop, not the different types of layouts that could be used. What I would suggest you do is the following: (1) study the Gridview example I did, so you can see an example of how drag-drop can work with a supported layout; (2) work with different layouts to get the end result you want displayed on the screen; (3) change DragLayer.onDragStart to locate the views within that are DropTarget implementations; (4) change the methods that actually do the drop of the view onto the DragLayer. That last one will be the tricky one because you have to remove the dragged view from where it started and add it at the new place. To position it correctly, you need to know what kind of view it is going to. In the code, this was in method onDrop of DropSpot. It used “mDragLayer.updateViewLayout(v, lp)”, with the lp value being a LayoutParams object that allowed placement at a particular x-y location — which is exactly the absolute layout problem. You need to do the drop with a layout parameter that works in your layout, which should not be an AbsoluteLayout.

        I suggest figuring out first designing your layout, then figuring out how to add a view at the various points you want to support dropping, but do it as a simple app where all you are doing is figuring out which layout params work where. When you understand that for your overall layout, go back and figure out who to add drag drop with that. The advantage is you’d know what the onDrop could should look like before you start.

  39. dejvid says:

    Hey,
    I’m using this nice tutorial. But i wonder if I can start dragging view from layout which is outside of DrafLayer layout ?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s