Improved Drag-Drop for an Android GridView

(March 4, 2013 Updsate: This example has been revised for Android V4, See Drag-Drop for GridView V4.)

I have an improved version of my tutorial app described in “Drag-Drop for an Android GridView“. It allows a drag-drop sequence to be initiated from any touch event. The earlier version required the user to do a long click (press) before dragging would start.

Download this demo application here: download from Wglxy.com. It was built with API level 8. Be sure to do a “Clean” rebuild in Eclipse.

Changes

This example application, like other ones I have done related to drag-drop, was based on the Android Launcher code. The Launcher required a long click (press) before an icon on the home screen could be dragged. Several people asked how to make it work on just a regular click. I finally got around to doing that.

To do this, all I had to do was make the activity implement View.onTouchListener. The handler  checks for the ACTION_DOWN event that indicates that the user touched the screen. If it sees that, it starts a drag operation.

public boolean onTouch (View v, MotionEvent ev)
{
 // If we are configured to start only on a long click,
 // we are not going to handle any events here.
 if (mLongClickStartsDrag) return false;
 boolean handledHere = false;
 final int action = ev.getAction();
 // In the situation where a long click is not needed
 // to initiate a drag, simply start on the down event.
 if (action == MotionEvent.ACTION_DOWN) {
    handledHere = startDrag (v);
 }

 return handledHere;
}

There is no right answer for the question: what starts a drag operation? It’s really your choice: long click or one touch. So what I did in the demo application is put a new variable into the DragActivity class. It indicates whether you want long clicks to be the only way to start a drag-drop operation.

private boolean mLongClickStartsDrag = false;
    // If true, it takes a long click to start the drag operation.
    // Otherwise, any touch event starts a drag.

So you can try out both ways of starting a drag-drop operation. Just change the value of the variable from false to true.

References

Input Events - describes the different types of input events for views: click events, touch events, etc.

Discussion about the touch events - the end of the note has a succinct statement about the differences

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.

104 Responses to Improved Drag-Drop for an Android GridView

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

  2. Pingback: Revue de l'actualité Android professionnelle du 4 mars 2012 | Paris Android User Group

  3. kranthi says:

    Hi ,

    wonderful , thank you so much. all images were placed in grid view , when i long-clicked one image which is placed in grid view and drag-drop on one image which is already placed in grid-view but they are not interchange the places…. if it is possible or not…? I wanna like this… plz tell me how to do..?m new to android…

    • blahti says:

      With a framework like this, you have to get comfortable with the interfaces for DropTarget and DragSource. In your case, concentrate on acceptDrop and onDrop in DropTarget. If you understand those and what the current demo does, I think you will see how to set up to accept a drop in a non-empty cell and how to interchange images between two cells. Note that the image cells know which cell they displaying. That would likely be needed to swap images between the two places in onDrop.

  4. Phanikanth says:

    Hi
    First of all Thanks to u ,these one is very help full to me,but my requirement is ,my screen had one grid view it contains 8 application ,if i add one more it will go to another screen, up to these i did successfully,but now i want to drag any application of second screen into first screen or vice versa ,hear i add view flipper to swipe screen change.

    • blahti says:

      The only place I have seen a drag-drop operation that starts on one screen and ends on another is the Android Launcher screen. You drag an app icon to the left or right edge of the screen, and that causes the whole screen to move to another page of icons. The Launcher code is where all of my drag-drop demo apps originated. I left that part out to keep this example simple. I would suggest getting the source code for the Launcher and studying their solution. See http://source.android.com/. In the source for API 8, the package was com.android.launcher2 and the top level class was Launcher.

      • Phanikanth says:

        Thanks for giving reply ,i tried same thing as u said ,but i am fail to drop my items to next screen,can u please a give sample code for these to drag items one screen to another screen..

  5. Oddie says:

    I have adjusted my code and it pretty much works the same as what I was working on yesterday. My issue is that if I touch one of the gridview areas, they act like the images instead of ignoring the touch event. These areas are empty of an image. I am going to keep looking for a solution, but thought I would also present it to you.

  6. Oddie says:

    I fixed my issue. Apparently there was some other differences in the files, and it is working perfectly. Thx again.

  7. Phanikanth says:

    Hi can you help me to solve my problem ,My intention is to drag my items of one screen to next screen,here i used grid view and view flipper to swipe can u please a give sample code for these to drag items one screen to another screen..

    • blahti says:

      Sorry to say that I do not know how to do that. It sounds like an interesting problem. I might work on that as a future project, but for now all I can suggest is that you return to the source code on which these drag-drop tutorials are based and study how they did it. The launcher2 package from API Level 8 is where I started. The full source code is something you would download from Android. Here is a link to just the launcher2 sources: zip of launcher2 package. Another thing to take a look at is the view pager article on the Android Developers website. Seeing how they do that might help.

      If you do succeed, it would be great to hear back from you. Sorry that I cannot do more at this time.

  8. Lee says:

    Hello blahti
    The project has helped you a lot.
    I have a question here.
    I would like to give each of the click event.
    But do not find the ID of the cell.
    Multiple images have floated from the beginning.
    And I would like to give a different turn the page.
    Could you tell me what is the link?

    • blahti says:

      Could you please provide a little more information about the app you are building and the problems you are trying to solve?

      • Cristiano Marinho says:

        Congratulations on the job, helped me a lot.
        maybe, I missed something too.

        I can not get the Id of the gridView cell used, how can i do?

        Thanks.

      • blahti says:

        If you look in ImageCell, you will see that it has an instance variable, mCellNumber, that is visible. That’s where you can get the index number of the cell. That values is set in ImageCellAdapter getView. Another way this information could have been shared is to use setTag on the ImageView as it is created.

      • Lee says:

        Has done the drop target when the application to re-run would be able to be maintained?

      • Supy says:

        Greate Tutorial . now i want to drop the images outside the gridview please can u help me

      • blahti says:

        In this example, you will see a Trash image. Images can be dragged there, and it is not part of the GridView. Study that. Basically, what is involved is adding a view that implements the DropTarget interface and then making that target known to the DragLayer. See onDragStart in DragLayer.

  9. R-Roadster says:

    Hi

    Just wanted to ask, I imported your project and I was getting a error to install it in the emulator. I noticed that in the manifest you have:

    but you don’t have a main xml. I changed it to DEMO and it installed. Just saying in case anyone is having the same issue.

    By the way this is an amazing example you got here. Is the first one I have seen and it really helped me to understand the Drag-Drop.

    Thanks

  10. Harry says:

    First of all I’d like to thank you for a great tutorial. I’m creating a slightly different app based on your tutorial where I have two dragable imagecells (I chose to have these both visible on screen rather than add them dynamically) and one gridview cell displaying above these. What I’m trying to achieve is getting the single gidview cell to only accept one of the two imagecells available. If the wrong one is dropped onto the gridview cell then it should snap back to its position. I’m slightly confused and could not get to the bottom of this. I’d be greatful if you could advise me. Many thanks

    • blahti says:

      Part of the DropTarget interface is a method named “acceptDrop”. It is a place where the DropTarget can tell the DragController whether it will accept something being dropped on. You could add some code in that method in ImageCell that checks the view being dragged to see if it is the kind of view that it accepts.

  11. R-Roadster says:

    Is there any way of knowing which image is connected with which image, so the program can do something else? For example if Hello is in position 0 and hello is in position 1 do something. Same if Hello is in position 0 and Hello in position 3.

    Thanks

  12. Adam Zinaty says:

    hello my friend
    thank you very much for this demo

    my question that how could i append a title below each image in the grid view

    amd i will be thank ful :)

  13. Ashish says:

    Hello Blahti
    I am facing a problem in your code when i do modify this code as per my project need, I got error every time, I am spending a lot of time to develop this but unable. Please have a look my question. I have images in gridview, only i want to drag an grid view item and drop it a spacific drop zone, How to implement. Have a look my [problem](http://i.imgur.com/AxiUm.jpg). Please give a solution, I am waiting for you.

    Thanks

    • blahti says:

      Every object on the screen that implements DropTarget has a method acceptDrop. It indicates whether it will accept a drop from a drag source. You’d have to write code there to return true or false, depending on whether the object being dragged can go there. If you have more than one top of drop target, you’d want to have two separate classes. One could contain the new code; the other would not. In general, you have to figure out where your drop zones are and what behavior you want; then add instance variables/methods so your activity code can set them up correctly.

  14. Anatolii says:

    Hi!
    Thanks for this solution! This is what I looked for!
    But I needed auto scroll for my GridView. So I improved this example to support auto scrolling. Also I changed base container view from GridView to AbsListView so now you can use ListView and other views that extends AbsListView.
    Here is my quick improve:
    https://docs.google.com/open?id=0BzFbjI8sMwpGS0JuamVOemRtb00

    Please, fill free to contact me.

    • Faisal Iqbal says:

      Hi Anatolii,
      I was exactly looking the same tutorial for my music player application where i need to drag songs from one list to another. But in your code once views are added they reappear after 5 cells. Your response and suggestion will be appreciated.

      • blahti says:

        When I started this tutorial app, I wanted it to include scrolling views. That proved to be difficult. So I went back to the basics of drag-drop onto a grid. I wanted the drag-drop part to be easy to understand. I had seen in the Android Launcher code (see Part 2 note) how complicated it got to do both dragging and scrolling at the same time. So the demo here was not designed to handle scrolling grid views.

        So what do you do to get scrolling? I will make a few suggestions.
        First, read the comments above for January 3, April 29, and May 9. A few other people had asked about scrolling. I have looked at the code a bit and found a few places to change so the views do not jump around. The big thing I did not do is to come up with a data structure to describe what is in the cells on the grid. In this demo, each cell keeps track of what image is displaying. There is no other place where that information is maintained. So when the adapter for the grid view starts recycling views it’s throwing away information. What has to be done is come up with a data structure, perhaps just an array in the activity, that stores what goes in the image view cells. The adapter needs to access that array in its getView method.

        Exactly what goes in the array is hard to say. If your app has images and all the images are in your resource drawable folders, it’s easy. Simply save the resource id numbers in the array. However, if you are allowing people to access images from their sd card or another app, you have to save a uri or path to the object in the array. Something like that should do the trick.

        Two more concerns: If you allow scrolling of the grid and also allow one image to be dragged from one cell to another, how do you know which is which? A user touches the screen inside a cell. Is that the start of a scroll or start of a drag? If you do support scrolling grids, you might have to use long-press to start a drag. And your touch event handling will still be tricky. Once a drag starts, which events will you pass through to the view handling the scrolling. I am sure it can all be done, but it will be a bit of work to get it done.

  15. hiren says:

    Thanks for your code. it really helpful to me.

  16. HongWoo Jin says:

    Hi, Bill
    Did you change only value from false to true about mLongClickStartsDrag ?

    If not, which files or method did you add or change ?

    • blahti says:

      All of the changes were in DragActivity. If you do File Search in Eclipse, you should find 8 lines.

      I wrote this up after the original article, but I did update the source link in the other article. Chances are the code you downloaded was using that variable.

  17. HongWoo Jin says:

    Hi, Bill
    Even if I compare this source than previous source, I cannot find any differences. what is meaning of “8 lines” ?

    As you know , even if I change variable of mLongClickStartDrag” to false
    it can drag and drop without long click.

    but I want to make long click drag & drop and onitemclick like android.
    please help me

    • blahti says:

      It sounds like you have the right source code. Eight lines had to do with the number of lines that matched Eclipse File Search.

      The variable is used to control what starts a drag operation. If you want long-click the value is true. If you want regular click, set it to false. The one that is most like the Android launcher is long-click, but that applies to an app like the launcher. There is no absolute right answer for all apps. You have to consider what is natural for your users. If regular click already means something — and it might in a grid view — I would suggest using long-click. For an example, see my note on horizontal scrolling views. I set it up so that long click was a zoom-in to details. I could not use regular click/touch since that was being used to scroll left and right.

      • HongWoo Jin says:

        If I set mLongClickStartDrag = false, then how can I execute regular click to execute specific application?

      • blahti says:

        The demo app works with that setting. You simply touch the screen and the images starts being dragged. When the value is true, you have to touch and hold your finger there for awhile. Long-press is what it takes to rearrange app icons on the home screen of your phone. I think of it as a design choice. What will feel more natural to users? Touch or long-touch?

  18. HongWoo Jin says:

    Hi, Bill
    I used to setTag on the ImageCellAdapter’s getView method as like parent.setTag(mThumbIds[position]);
    but even if I use onclick method
    GridView gridview = (GridView) findViewById(R.id.image_grid_view);

    assert(R.id.image_grid_view == gridview.getId());
    Log.d(“TAG”, “TAG OF GET” + gridview.getTag());
    Integer integer = (Integer) gridview.getTag();
    integer = integer == null ? 0 : integer;

    switch (integer) {
    }

    unfortunately, imagecell have at least 8 images, but even if I click anything image , only one get tag values , that is to say
    there are 8 different images on the gridview, even if I click anything, it only run only one intent.

    • blahti says:

      I don’t think it is the parent (gridview) that you want to set the tag in (parent.setTag). I think you should be setting the tag of the ImageCell itself. Then you will want to copy that tag value in the onDrop method. Then later, when the cell is clicked on, you get the value from the image cell (getTag). It looks like you will then use that value to see which intent to start (your switch block).

      • HongWoo Jin says:

        Hi, Bill

        onDrop method is related to drag and drop , right?
        I think it does not need to copy that tag in the onDrop mehod., for onTouch. this function I think it needs to relate android preference for drag and drop , right?
        Even if I set tag on the ImageCellAdapter’s getView method, then dragActivity’s touch method call getTag.
        but it returns null value

  19. HongWoo Jin says:

    Hi, Bill
    I’ve finally understood your request, but I don’t know where to and how about input about settag on the ImageCell.
    Can you give me a hint more please?

    • blahti says:

      I am not sure you understand the drag-drop code framework. Go back to Part 2 of my Drag-Drop posts. You need to understand which pieces of the code run when an object is touched and picked up and which ones run when something is dropped. The interface classes are DragSource and DropTarget. Once you have the framework classes understood, return to the GridView example. See how those same classes are using the same framework. ImageCell implements both of those interfaces. onDrop is where information gets copied from the moving cell to the target cell.

      • HongWoo Jin says:

        If I have set false about mLongClickStartsDrag variable, it works touch method, but mLongClickStartsDrag sets true works onClick or onLongClick. and if you try to longclick , it acts with onDrop method. If I setTag on ImageCell itself, How can I do it? Even if I add to ImageCell constructor, it makes error.
        sorry to bother you , but I have to make this app , please help.

      • blahti says:

        I am sorry. There is not much more I can do. I do not wish to be unhelpful, but I think you need to go more slowly and develop a deeper understanding of what is going on in the code. Go back to the original working example. Make one change at a time and verify each step. Use the debugger and Log.d statements if you have to. You need to understand the existing code before you can make changes. It is going to be difficult because there are many different features of Android being used. Related to use of setTag, see my recent comments to Andy. He is asking something very similar to you.

  20. HongWoo Jin says:

    Hi, Bill

    Is it able to change images to imagebutton on gridview?

    • blahti says:

      Yes. It should be possible to put any type of View inside the grid. For an image button, you have the problem that we’ve already discussed. What does click mean? If you put live buttons in the grid, you will want a click to mean what it means for a button — do my action. In that case, you have no choice but to make dragging be initiated with a long click (press).

  21. HongWoo Jin says:

    Hi, Bill
    No matter how I check onDrop method, I conclude this method is related to Drop.

    Phase 0 : Is it possible to change images to imagebutton?

    Phase I : onClick
    I don’t know how to get Resources information from View

    Phase II : onItemClick
    To implement OnItemClick on Activity, I dont’t know to run this function

    • blahti says:

      RE – Question on onClick.
      I agree. I don’t think there is an easy way to the resource id of a view. I have tried this a couple of times without success. I think you can get the Drawable, but not the resource id. That means you have to store the resource id somewhere. If you are using ImageCell, add another instance variable and save it when you know what is being dropped there. Later, when you access the cell outside the drag-drop, locate the ImageCell and use the extra information you put there.

  22. HongWoo Jin says:

    Originally setOnItemClickListener is not working of this example?
    No matter how I check , GridView’s cell cannot select and any focus.
    If I work drag and drop with long click and onitemclick, how can I do it?

    • blahti says:

      Yes. I never figured out how to get setOnItemClickListener to work. When I tried it, it interfered with drag and drop working. If you choose to have long click start a drag, you could change the onClick handling of the ImageCell. Perhaps that would get you what you want.

      • HongWoo Jin says:

        Bill
        ImageCell returns mCellNumber as index, but in case of drag and drop only needs to resourdce name or full path.
        How can I get it? If I use hashmap, is it ok?

      • blahti says:

        I know of no way to get the id of the resource in an image view. You’d have to add an instance variable to ImageCell and set it in getView of the image adapter and in onDrop of the ImageCell. Then later, when you want it for your next step, you’d get it from the place you saved it in ImageCell.

      • I am trying to detect which item was clicked and subsequently access a data item from a list i have passed into the data adapter (based on which position was clicked). How exactly can i do that if im happy to only drag on long click?

        I have tried to get the following to be called but failed multiple times:

        gridView = (GridView) v.findViewById(R.id.image_grid_view);
        gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        // never gets called?
        public void onItemClick(AdapterView parent, View v,
        int position, long id) {
        Log.i(TAG, “An item was clicked”);
        // further processing …
        }
        });

        I have commented out the following in my ImageCellAdapter equivalent, but that does not help:

        // v.setOnTouchListener((View.OnTouchListener) mContext);
        // v.setOnClickListener((View.OnClickListener) mContext);
        v.setOnLongClickListener((View.OnLongClickListener) mContext);

        I suspect the problem is that the DragLayer is not routing some event as normal, but im not sure what touch or click event OnItemClickListener relies on? Would it help to make DragLayer only intercept events after dragging has started – how would one do that if that would work?

        Thanks again!

      • blahti says:

        Yes, I’d agree with your analysis. The DragLayer has onInterceptTouchEvent and onTouchEvent defined and the GridView is inside the DragLayer view. So I think that alters the normal click handling of the GridView.

        Something that might work is to wait until there is a drag method called. Rather than doing your “further processing” at the time of the click, see if you can do it in one of the methods of the DragSource or DropTarget interfaces. For instance, you might try allowDrag of the ImageCell. The cell knows it index number (in mCellNumber) so at the point it’s asked if it should allow the view, you’d be able to take the index number and get to your other data. Or if you wanted to wait until the drag-drop ended, there is method onDropCompleted. I’m not sure what you want to do at click time, but it might work out to defer it a bit.

  23. sir i have a question im creating a game and i want to drag and drop an image to a specific area and i want to confirm if the image was the correct one .for example the question would go like this:
    which of the following is the largest
    (image of different numbers)
    the user must drag and drop the image to a specified area how can the program check if it is the right number?

  24. Thanks for sharing your expertise! I am trying to extend your work to allow views of different size to be included inside your viewgroup, but the GridView on itself does not allow different column widths or row heights to my knowledge (http://stackoverflow.com/questions/7817979/can-grid-view-have-column-spanning-one-or-more-rows). Could you please advise regarding what approach would work? So far I have gathered two ideas 1) Replace your GridView with a TableLayout, but the big disadvantage of that is that it is not possible use adapter data binding any more, because TableLayout is not an AdapterView 2) Use a root GridView with large children dimensions, but in the adapter getView return a view that contains an embedded GridView, and then populate the outer GridView if the item is to be large or delegate the item to the inner GridView if the item is set to be smaller size?

    • blahti says:

      I have only tried GridViews for images. And they impose a standard size for all images. If you did use a TableLayout, you could still arrange to do drag-drop of images between different cells. You’d want something like the ImageCell class and you’d use that for your images. Your replacement for DragLayer would need to know how to find those image cells so they could be set up as DropTargets. That’s in the onDragStart method. Your DragLayer would go through all of its child views, in search of those that implement the DropTarget interface. So you’d have to do something like “v = (DropTarget) childView” inside a try-catch block so you could ignore the child views that are not DropTargets.

      And if you are doing this in new code, you might want to consider using the new drag-drop framework that started with Android 3.2. You might find that easier because it already has its own scheme for identifying which views are targets. I have not used that yet, but it looks like a good interface.

      Whichever one you use, your big challenge will be getting the images sized they way you want them. I have several times been tempted to do a custom layout for images, but have not done so yet. It would be nice to hear back from you to see what you come up with.

      • Thanks for the reply! I’m gonna try soon and will let you know; for that matter, have you considered putting your code up in some source control repository so others can contribute to it more easily?

  25. dubepuneet says:

    Hi Blahti,

    Thank you for your precious effort, I am trying to swap image from in Grid, when i drag one image to another they should swap(Interchange) there Grid, I tried a lot in onDrop() and dropTarget() methods but still i am unable. can you please help me.

    • blahti says:

      In order to swap images, you need to know which images are in the cells. This demo did not keep track of that. You could add something in ImageCell to identify the drawable in the cell. Then, at time of drop, look at the source cell and the target cell, and swap the images. I think there are a few interesting cases: (1) images identified by resource id; (2) images coming from a path on the sd card. You might be able to save the bitmap object with the cell, but then you have to worry about running out of memory. If you want to go that way, read “Loading Large Bitmaps Efficiently“.

  26. dubepuneet says:

    Hi Blahti,

    I want to create a puzzle game where we have two array, one image array contains 100 images and another one contains 100 characters, when i start my game it will select ant 9 images from image array and the corresponding characters from another array, now i have to display images and characters in wrong order, user will rearrange these image in write order match with characters, I am unable to display all images and swap them when a user drag and drop an image on one cell. can you please do this for me, i am stuck :(

    • blahti says:

      Take a look at my blog post on Image Squares. That does something similar to what you are describing. It fills in a grid with images that are chosen randomly from a set of 8 images. Perhaps you could merge parts of that adapter with the one from this GridView demo app and have a pretty good starting point. It sounds too like you will need to find a place to store a number that indicates the sort order of the images and characters. You could consider adding that to ImageCell, or whatever class you end up using to hold your images.

  27. Hi blahti,
    I want to add static an ImageCell into ImageCellAdapter without using drag-drop on onCreate method. How to do it?
    Thanks!

    • blahti says:

      Take a look at onDrop of ImageCell and getView of ImageCellAdapter. Those two will give you a sense of how images get onto the grid. You’d have to do something like that ahead of time in your setup code for you activity. Something like this might work:
      getView is the method that says how to fill up a cell. If you wanted cell 4 to always show a particular image, change the code in getView to create an ImageCell that is preset with your static image. Set mEmpty to false. You might also want to add another variable in ImageCell to record the fact that the cell does not allow further drag-drop (if that’s the effect you are after).
      There are probably other ways, but that’s one to consider.

  28. Joanne says:

    hi. this is something helpful for my app. I’m just wondering if it is possible to drag a textview that contains a text and drop it to an imageview. and then, it will get the text from the text view and assign it to the imageview.. something like this… .. thanks. :)

    • blahti says:

      Yes. That is possible, but you will have to take the text and write it onto a bitmap and then assign the bitmap to the image view. You also have to make your own subclass of TextView so it can implement the DragSource methods.

      • Joanne says:

        hi again. i’m just wondering if its possible to arrange the grid view in a different form. like if the orientation is on landscape, there are 10 (box)gridview on the left side and another 10 on the other side like a seat plan in a class room?. thanks

      • blahti says:

        On a tablet or in landscape, there certainly could be room to put a grid of images on each side. If you work through the steps one at a time, you should be able to achieve it. Start by building an activity with two grid views on each side, with something in the middle, like a text view. Then look at my example and understand the difference between standard grid views and the one I used to support drag-drop. Then it gets a bit harder. You have to understand how the DragLayer ties in to the DragActivity because you will need a DragLayer in your new activity, the one with two GridViews in it. Look at how onDragStart looks through its child views to locate the ones that are drop targets. You would do something like that but you’d only look for the cells in your two GridViews and you’d ignore any other child views, like the text view or whatever is in the middle of the screen, separating the two grids. If your two grids had cells that implement DragSource — and you might be able use the existing ImageCell — I hope you can see how you can drag images from one of your grids to the other.

      • Joanne says:

        thanks a lot! somehow my problem is similar to this thread. http://stackoverflow.com/questions/13568256/android-how-to-customize-gridview-layout-dynamically … regarding the customization of the GridView.. i hope you can help me. but i’ll try first what you have told me to do so. thanks.

      • blahti says:

        I had a similar problem when I was working on horizontal scrolling. I wanted to the number of cells on the grid to vary dynamically. For example, I wanted 1 x 3 for landscape and 2 x 2 for portrait. Then, for tablets, I wanted 4 x 8 for the display. I found a way to do that using the size qualifiers for the resource values folder (e.g. values-sw600dp). See my note on horizontal scrolling.

        Another experiment with a dynamic grid view is written up in my Image Squares post. It shows how to build a square grid when you do not know ahead of time how much room you have to work with. It uses one of the layout observers that you can do. That might also help you come up with a way to size things on the fly.

  29. Sallu says:

    Hello
    How to add scrollview in this tutorial because when I add scroll view then image move at another place and drag doesn’t work
    Can you help me ?

    • blahti says:

      I chose not to address scrolling in this demo app. I wanted to make it easier to understand the drag-drop part.

      I don’t know if you saw the comments I made about scrolling. Look for the comments around June 7 and August 8. On the original GridView post, there are also some comments on January 4, 2012. I know that’s not a complete solution, but I hope it helps some.

  30. David says:

    Hi, Thank you very much for your tutorial and i saw you have replied to all the one who have asked help.Special Thanks for that.

    I have used your code in my Project.It seems to be fitting good.
    My requirement is When the user add and drag images on the gridview .When they logout and login now when they come to grid view page again all the images which they have placed in the image cell must be there and those images also must be draggable.

    So i thought of storing the cellno and the resource id in the database.
    I got the cell no from onDrop method.i tried to setTag in DragActivity on void addNewImageToScreen (int resourceId) method

    newView.setTag(myIds, “test”);

    How can i get this value in the onDrop method.I tried getTag(myIds), but it results in error.

    How can set the images (which are already placed by the user on the Grid view).I tried using getView method but could not get it.Eventhough if i placed the image on the gridview it must be draggable.

    Thank you sir for spending your precious time in reading my question.I am waiting for your response.Thanks for your patience once again.

  31. David says:

    Hello Bill, I have found out how to set resource id for an image and get the Resource id in onDrop method.Now i get both the cell number and what image is present inside the cell

    I have added code as follows
    DragActivity.java
    mthod -> addNewImageToScreen (int resourceId)

    newView.setImageResource (resourceId);
    //Set the id for an image it can be any integer i have set resource id
    newView.setId(resourceId);

    And i get this resource id at
    imageCell.java
    method->onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
    DragView dragView, Object dragInfo)

    if (d != null) {
    this.setImageDrawable (d);
    /**Added Code**/
    this.setId(sourceView.getId());
    int imgId = sourceView.getId();
    System.out.println(“The cell no is “+mCellNumber);
    System.out.println(“The Image id is “+imgId );
    /**Added Code END**/
    }

    I will store the cell no and the image id in shared preference and then to db.

    Now my question is when i get the cell no and image id from DB.how can i set the image to a particular cell in Grid view and make it Draggable
    Suppose for ex i am going to set an image to cell no 3 and make it as Draggable as usual.

    Bill I need the insight on how to implement this.

    I need your help..Thanks Again for your patience

    • blahti says:

      I am not sure what you are after here. The view id is id assigned in the layout xml file. That is not the same thing as the resource id of the image that was used to set the drawable of the ImageView. I think you will have to add another instance variable to image cell that can hold the current resource id being used.

  32. David says:

    Hi Bill now i have found out how to set an image to an individual cell in Grid view.Suppose if i want to set an image to cell number 3…
    In Imagecelladapter.java
    Method -> getView

    I have added this

    if(position == 3)
    v.setImageResource(R.drawable.velux);

    yes the image is added to cell no 3..But it is not dragging as other images ..How can i set it draggable?

    I am a newbabie to Android..I need your help…Thanks Again for your patience.

  33. David says:

    Wow Praise Jesus I have found that solution too…

    I can make that image draggable by just setting mEmpty = false

    ImageCellAdapter.java
    mthod -> getView

    I have set

    if(position == 3){
    v.setImageResource(R.drawable.velux);
    v.mEmpty = false;
    }
    and this thing does the trick.

    Thank you very Bill for your Wonderful Code which does really awesome things.GBU

    • blahti says:

      If you check the getView method of the original ImageCellAdapter, several things get done, including setting mEmpty and setting up touch and click listeners for the ImageCell. Try to match the set up there. I am not sure how setting mEmpty false is going to make the object draggable. I think it’s going to be setting the touch listeners.

      • David says:

        Thanks for your Reply.I have set mempty = false for the a particular as i have wriiten the code above…Yes it is working fine..The image when i touch it starts dragging…
        Can you please test by yourself and let me know if i have gone wrong somewhere
        Below is my getview method for ImageCellAdapter.java

        public View getView (int position, View convertView, ViewGroup parent)
        {
        mParentView = parent;
        ImageCell v = null;
        if (convertView == null) {
        // If it’s not recycled, create a new ImageCell.
        v = new ImageCell (mContext);
        v.setLayoutParams(new GridView.LayoutParams(50, 50));
        v.setScaleType(ImageView.ScaleType.CENTER_CROP);
        v.setPadding(8, 8, 8, 8);

        } else {
        v = (ImageCell) convertView;
        }

        v.mCellNumber = position;
        v.mGrid = (GridView) mParentView;

        //v.setBackgroundResource (R.color.drop_target_enabled);
        v.setBackgroundResource (R.color.cell_empty);
        if(position == 3){
        v.setImageResource(R.drawable.velux);
        v.mEmpty = false;
        }
        //v.mGrid.requestDisallowInterceptTouchEvent (true);

        // Set up to relay events to the activity.
        // The activity decides which events trigger drag operations.
        // Activities like the Android Launcher require a long click to get a drag operation started.
        v.setOnTouchListener ((View.OnTouchListener) mContext);
        v.setOnClickListener ((View.OnClickListener) mContext);
        v.setOnLongClickListener ((View.OnLongClickListener) mContext);

        return v;
        }

        Thank you very much for your patience once again

  34. Albert says:

    sorry my bad english,but I have a gridview with images load from urls, I don´t need a button for add images to gridview, only i need drag and drop images loads in gridview to trash but event ontouch and onclick dont work, I think because I dont add images from button to gridview. Can you help me?

    • blahti says:

      Look at the code for getView of class ImageCellAdapter. That is where the touch and click listeners are set up for an ImageCell view. Whatever way you get your images into a grid, you will need to make sure touch events and click events get relayed to the drag controller objects.

  35. Your project was inspiring! Thanks

    My own implementation demo video:

  36. Hi! How can I change the image/color (red tile) that is left after an item is dragged over? (for example – if I wanted to change it to a blue square or a drawable)

    http://stackoverflow.com/questions/20790680/changing-ondragover-event

    • blahti says:

      You will need to come up with a custom class to define the items that go in the gridview. That view would display the text and an image. Have the new class implement the drag-drop interfaces. In the acceptDrop method copy both the text and the image.

      Part of the problem you face is similar to having a custom list item with a list view. It might be good to find a few examples of that before you take on the drag-drop part.

      • Jacob Smith says:

        For now – I’d simply like to have a static textView dragged and dropped with each image – do you think that’s something you might be able to assist with? (I’m sorry to bother you again – I’m just having a bit of trouble figuring out a simple method of accomplishing this)

        http://stackoverflow.com/questions/20963115/android-java-add-textview-to-drag-drop-gridview-tutorial-example

      • blahti says:

        I’d start by breaking the problem down into two parts: (1) Figure out how to do a simple app that uses a GridView to show and image with text; (2) From #1, take the view class you use and build a subclass of it so you can support the methods of the drag-drop protocol.
        The closest thing I’ve done for #1 is part of Horizontal Scrolling Pages of Images. The images in the GridView all have labels. I don’t think there was a specific class for that, but I wonder if the view class you need would be a subclass of FrameLayout.

        That’s what I would do if I had time — and sorry to say, too many active projects right now to do more.

  37. Yisus LLamas says:

    HOLA soy jesus no entiendo poq m salen varios errores la verdad stoy aprendiendo sobre android. Algunos de ellos son:
    image_source_frame
    delete_zone_view
    integer.num_images
    cell_empty
    cell_filled
    cell_empty_hover
    estos ultimos creo es relacion con los colores q noc poq hay problema y los demas ni idea. Espero m puedas ayudar saludos y gracias…

    • Bill Lahti says:

      I am sorry, but I may not understand your question. I ran it through Google Translate and got the impression that you were asking about colors.
      The color definitions are in an xml file: colors.xml. That file is in res/values folder.

      • Yisus LLamas says:

        Lo que pasa que descargue todos los archivos del link que usted puso. Y al momento que los importe en mi aplicación me salieron estos errores:

        image_source_frame
        delete_zone_view
        integer.num_images
        cell_empty
        cell_filled
        cell_empty_hover

      • Bill Lahti says:

        If the project does not compile when you first load it, rebuild it completely with “Clean” on the Eclipse Project menu.

  38. Yisus LLamas says:

    HELLO:
    MY error is: CANNOT BE RESOLVED OR IS NOT A FIELD (cell_empty, cell_filled, cell_filled_hover, cell_empty_hover, num_images).
    I think it’s something about the colors.

    • Bill Lahti says:

      A few things for you to look for:
      (1) Check that there are no syntax errors in the colors.xml for dimens.xml files. (2) Does the original demo code compile cleanly and the problem is in your new code? If it is, look for differences in structure. (3) If you have a package com.c.demo, classes defined in that package will find the generated R class that defines constants for resources. If you are in another package (say com.c.demo.ui), you need an import statement like “import com.c.demo.R” at the top of your class file. (4) If there is an error in your AndroidManifest file, it might cause the files not to compile cleanly. (5) If you are working on a different Android version than this demo was built with, sometimes I have had to go to Project Properties and switch the Android version back and forth. (6) Do Project-Clean, maybe even in combination with some of the previous suggestions.

  39. HongWoo Jin says:

    I think if I add intent statement to Touch method, it will run as I hope. but I don’t know how to get resource id from View v? If I check R.java , it shows resources as integer. or Do you have any solution to run onItemClick?
    On the gridview can only run setOnItemClickListener,

    If I bother you asking about this question, please forgive me.
    But I have to make this app asap.

  40. blahti says:

    You could try saving something in the view’s tag field (setTag) to indicate which image is in the cell. If your images are all in your app, the resource id of the image would work. If some of them come from downloads, you would want to save the path on the sd card.

    I’ll send you a separate email to address the other questions.

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