Search This Blog

Loading...

Friday, October 29, 2010

Experience - Android Drag and Drop List

I am continually surprised by the fact that the things I need for my application do not exist in android. This time I needed a drag and drop list. I have been unsuccessful in finding a simple, working drag and drop list that I can extend. I have seen numerous places that reference android's music app as a starting place. The main classes of importance from the music app were TouchInterceptor and TrackBrowserActivity. Many of the examples that I have seen struggled to use it well and most ended up having serious problems as a result. I would rate the TouchInterceptor code with a rating of "F" because it is not simple and it is not easily extendable. Check out this article for a way to rate code. It left a good impression on me.

This experience is about my efforts to build a simplified drag and drop list. I hope time will prove that it is easy to extend as well. The first task was to get a copy of TouchInterceptor and TrackBrowserActivity running in a simplified project. This took time because of all the dependencies and interconnections between these two classes and the rest of the app. As I look back on the matter the only real benefit this provided me with was a better understanding of how not to make TouchInterceptor work. After I had a runnable project, I attempted to modify the drag animation from an expanding/contracting items on drag to one that rearranged items in place. I was almost finished with this change when I ran into a technical issue that I didn't want to spend time to fix. I then discovered that the Launcher app provided a better drag and drop example because it was simplified compared to some of the complex interactions in the music app. Using both the music app and the launcher app as a reference I wrote a simplified drag and drop project. You can find the project here.

I wanted to provide methods that allowed modifying/customizing the view of the item being dragged, but not fall into the same complex interactions of the music app. I chose to use the DragListener with the intended purpose of handling view changes. In the sample project, I made the item's view invisible to show where the drag view came from, and I changed the background color to show that a drag view is different from the rest of the item views. It is important to revert any changes to the item view because it will be recycled back into the list view for item views.

This project code is simply to share a simple working drag and drop list since I was unable to find one elsewhere on the web. If you add any extensions to this simple project I would like to hear about it in the comments.

172 comments:

  1. This is excellent, far easier to understand than TouchInterceptor. Is this released under any particular license? I'd like to use it in a commercial/closed-source project. Thanks!

    ReplyDelete
  2. @Jeffrey I have not specified a license in the source code yet. Use it in accordance with Apache 2.0 Thanks for the reminder for me to specify the license.

    ReplyDelete
  3. Hey I got some checkboxes on the view i'm dragging/dropping.

    On drop they aren't chackable anymore, I have to hide them (scroll) to re enable them.

    I tried invalidateviews on the list, notifyDatasetChanged/Invalidate on the atapter, it's the same, any idea ?

    ReplyDelete
  4. @VV I am having trouble reproducing your issue. I just took the sample code and modified the dragitem.xml to be a checkbox. Then I rearranged the items and checked all the check boxes. No problems. If you are still having an issue with this could you explain the steps to trigger it.

    ReplyDelete
  5. Thank you for your example, great help! but I don't know is anyone get the problem when clicking the items too quick? I got an exception when I was dragging and dropping the items repeatedly in a very short time, like 0.1 second. so i need to prevent the double clicks in DragNDropListView:
    ...
    private static long lastTouchTime = -1;
    ...
    public boolean onTouchEvent(MotionEvent ev) {
    ...
    if (action == MotionEvent.ACTION_DOWN && x < this.getWidth()/4) {
    mDragMode = true;

    // check is double clicked within 2 seconds
    if (System.currentTimeMillis() - lastTouchTime < 2000) {
    mDragMode = false;
    }
    }
    ...
    private void stopDrag(int itemIndex) {
    ...
    // save the last touch time
    lastTouchTime = System.currentTimeMillis();
    }
    ...

    it seems can solve the exception, but i'm not sure is only my simulator or phone problem... hope can help if others have that problem

    ReplyDelete
  6. I saw this issue when I created my Drag and Drop List. It was an unfortunate carryover from the music app in the android repository. I like your code snippet. Thanks for sharing it.

    ReplyDelete
  7. Excellent example! Thanks for sharing this! :)

    ReplyDelete
  8. I too added a checkbox to the dragitem.xml:







    If I check the first item in the list and then move it to be second item in list, then for me the 10th item in the list is checked and the check is missing from the item I checked (hope that makes sense). If I move it back again, it is check as it should be. I guess this is something to do with the way ListViews reuse views... not figured it out, but thought I'd mention it here until I have! Maybe you have a solution?!

    Also, can I make the entire ListView entry make the item movable? Currently it is only the left of the ListView item (Image in your sample) but if I move the image to the right, then it no logner works and I have to use first part of text to move item entry. Can't see where to sort this one....

    Otherwise, as I said above, excellent example! :D

    ReplyDelete
  9. @Neil Deadman Thanks for the easy steps to follow. Now that I see the checkbox issue I have an idea. Try modifing the DragNDropAdapter. It is currently designed specifically for dragitem.xml to be a TextView. You will probably need to modify ViewHolder and possible mContents to be able to hold the text content and the checked state. Be sure to set/update the text content and checked state in the Adapter's getView(). Hope this is descriptive enough to figure out the rest of the details.

    As for your second question look in DragNDropListView's onTouchEvent(MotionEvent). You could change the line of code that reads

    if (action == MotionEvent.ACTION_DOWN && x < this.getWidth()/4)
    {
    mDragMode = true;
    }

    to something simpler like

    if (action == MotionEvent.ACTION_DOWN)
    {
    mDragMode = true;
    }

    ReplyDelete
  10. If you go crazy draging the rows around you can make the example crash at line 88 in DragNDropListView.java with the following error:
    12-29 14:21:33.793: ERROR/AndroidRuntime(11715): at com.ericharlow.DragNDrop.DragNDropListView.drag(DragNDropListView.java:88)

    Nothing a try/catch can not fix :)

    ReplyDelete
  11. Almost forgot - Great example!! Will use this as base for my own drag'n drop stuff. However as this is list views I would recommend that the x parameter is ignored so the list rows are only dragged up/down and do not follow the hand around the screen.

    ReplyDelete
  12. Great work!
    I was trying to add this as a custom preference but I can't get the Drag/Drop Listeners to work.
    Any ideas?
    Thanks a lot.

    ReplyDelete
  13. @CS Shenouda I have never tried to add Drag and Drop as a custom preference. I do like the concept. Are you getting a repeatable error or crash? How could I repeat it?

    ReplyDelete
  14. No error.

    I extend ListPreference.
    In onPrepareDialogBuilder I do this:

    DragAdapter = new DragNDropAdapter(getContext(), new int[]{R.layout.dragitem}, new int[]{R.id.TextView01}, entries);

    builder.setAdapter(DragAdapter, new DialogInterface.OnClickListener()
    {
    public void onClick(DialogInterface dialog, int which)
    {

    }
    });

    I just don't know how to add the drag/drop/remove listeners in the ListPreference.

    At the moment I solved it by just launching it as an activity from my preference screen.
    Still for the sake of reusability it would be great to make a custom ListPreference :)

    ReplyDelete
  15. This is neat - it helped me get past a problem I wasn't able to figure out from the Android music app source. One quick question -- I am unable to drag/drop past the current view (i.e. if I have 20 rows, but only 5 rows visible, I can't drag row 0 past the 5th row). Any ideas why that would be? Essentially, the ListView in the background isn't scrolling.

    ReplyDelete
  16. @Viraj Mody The reason drag and scroll doesn't work is because that code was striped out of this example.The music app has this code that you could add back in and adapt as needed.

    ReplyDelete
  17. @Eric Harlow Thanks - I did. Made a couple of other changes too:

    - limited drag to y-axis only
    - implemented ability to delete row by swiping left (not using Gestures). Did this by allowing movement along x-axis only for the dragging row, and computing if the touch-up occurred in the last 3/4 of the row.

    ReplyDelete
  18. @Eric Harlow Thanks for your reply. I've implemented the changes to allow dragging from anywhere, and also to only move along the y-axis (as other posters commented). I'm still having problems figuring out how to retain the state of the checkbox.

    I made my own class to use instead of String in:

    mContent = ArrayList (old)

    mContent = ArrayList (Mine)

    When I drop a dragged row, the onDrop method gets the row I'm moving, but inspecting the values, the checkbox state is still false.

    I assume that when I check the checkbox, the value held in my class for that entry in the ArrayList is not being updated.

    My problem is how to do this?

    I'm by no means an experienced developer, so I hope you are able to assist me!

    Thanks!

    ReplyDelete
  19. @Viraj Mody

    Could you possibly post your modified version of the code? I am trying to do both of those things in my app, and seeing your solution would be much easier than trying to figure it out on my own...I don't have much experience with touch events.

    ReplyDelete
  20. @Neil Deadman Originally I had tried to put everything related to drag views into the DragListener, but in your case this doesn't work as well. A better solution for your case is to create an onClickListener and attach it to all of the CheckBoxes. One way to accomplish this would be to add the below member variable to DragNDropListActivity.

    private OnClickListener checkBoxListener = new OnClickListener() {

    public void onClick(View v) {
    View view = (View)v.getParent();
    int index = getListView().indexOfChild(view);
    ListAdapter adapter = getListAdapter();
    CheckBox checkBox = (CheckBox)view.findViewById(R.id.CheckBox01);
    ((DragNDropAdapter)adapter).updateItem(checkBox.isChecked(), index);
    }
    };

    Note my onClick() assumes dragitem.xml is a LinearLayout with a CheckBox as a child. Add the onClickListener as a parameter to DragNDropAdapter's constructor. Also add the following bold lines in DragNDropAdapter's getView().

    // Creates a ViewHolder and store references to the two children views
    // we want to bind data to.
    holder = new ViewHolder();
    holder.text = (CheckBox) convertView.findViewById(mIds[0]);
    holder.text.setOnClickListener(mCheckBoxListener);

    mCheckBoxListener is just a member variable in DragNDropAdapter that stores the onClickListener from the parameter in the constructor.

    // Bind the data efficiently with the holder.
    ViewContent content = mContent.get(position);
    holder.text.setText(content.text);
    holder.text.setChecked(content.isChecked);


    ContentView is just a class that holds the text and a checked state for a CheckBox. Sounds like you already have an equivalent class. The last thing you should need in DragNDropAdapter is

    public void updateItem(boolean isChecked, int index) {
    mContent.get(index).isChecked = isChecked;
    }
    and you should be good to go. I can email you the entire project if you run into trouble. Best of luck!

    ReplyDelete
  21. Thanks for this great example. I'm trying to modify this so that a user can edit the list by clicking on the items and selecting options through dialogs. So I've been able to get a concept working, except that the ListView will not update. If I step through the debugger, the item changes in the array and the dialog correctly gets the right item, but change does not show in the list on the screen. I believe that I need the notifyDataSetChanged() method, but I cannot figure out what to attach it to and where to do it. Can you help?

    Below is my modified code in DragNDropListActivity for onCreate() and the additional dialog (hopefully it's readable):

    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mListContent.add("static1");
    mListContent.add("static2");
    mListContent.add("static3");
    mListContent.add("static4");

    setContentView(R.layout.dragndroplistview);

    ArrayList content = new ArrayList(mListContent.size());

    for (int i=0; i < mListContent.size(); i++) {
    content.add(mListContent.get(i));
    }
    setListAdapter(new DragNDropAdapter(this, new int[]{R.layout.dragitem2}, new int[]{R.id.TextView01}, content));
    ListView listView = getListView();

    listView.setClickable(true);
    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView a, View v, int position, long id) {
    tempselect = Long.toString(id);
    selecteditem = Integer.parseInt(tempselect);
    showDialog(1);

    }
    });

    if (listView instanceof DragNDropListView) {
    ((DragNDropListView) listView).setDropListener(mDropListener);
    ((DragNDropListView) listView).setRemoveListener(mRemoveListener);
    ((DragNDropListView) listView).setDragListener(mDragListener);
    }

    }

    public Dialog onCreateDialog(int id) {
    switch (id) {
    case 1:
    tempstat = "changed";
    mListContent.set(selecteditem, tempstat);

    AlertDialog.Builder adb = new AlertDialog.Builder(this);
    adb.setTitle("LVSelectedItemExample");
    adb.setMessage("Selected Item is = " + selecteditem);
    adb.setPositiveButton("Ok", null);
    adb.show();
    }
    return null;
    }

    ReplyDelete
  22. Never mind. I figured it out. I was only updating the array and not the content of the listview. Also figured out where to call notifyDataSetChanged(). I can post code if someone else is trying to do this.

    ReplyDelete
  23. Hi Everyone, i'm just new to android. i been searching a grid layout that can drag and drop the item. It seems that Eric have the right one that i been looking for, but the problem is that it display in list can you gave me an example of displaying it in a gridview. thanks...

    ReplyDelete
    Replies
    1. Hi Jainey, I'm also looking for a grid layout that can drag and drop items. Have you find a solution in the meantime?

      Delete
  24. How could I use this to extend what simple cursor adapter does? Right now i'm trying to replicate what simple cursor adapter does inside of DragNDropAdapter on top of the drag n drop function but that uses ViewBinder while yours is view holder.

    I'm looking how I can make drag n drop using entries from a database and using a cursor rather than just static text. Any suggestions?

    ReplyDelete
  25. Does anyone already tried to update it so that it automatically creates a gap between 2 items while moving (like in the current music application)?
    For me it is a bit confusing where to drop the item now.

    ReplyDelete
  26. @Eric Harlow Sorry for disturbing for asking such a chilly matter, would you please give an example which support drag, scroll and drop in list view, i am a novice developer i try to modify music app but is not work but i understood your example. Thanks in advanced.

    ReplyDelete
  27. This does not seem to work that well in a layout where the ListView (DragNDropListView) does not fill the whole display. For example i you have some other elements on the top of the display and this list should be shown beneath.

    Has anyone experienced the same problem and have a solution?

    ReplyDelete
  28. This is great! Thanks!!
    I've got this up and running in my app. Ideally, my app will allow users to choose items from different lists to decorate a background image.

    Any way to drag items *out* of a list back to a previous view/screen?

    Essentially I want the progression to be:

    screen1>click menu>click button to show list of items>item appears back on screen1

    Sorry if I'm not asking this right.

    ReplyDelete
  29. its really gr8 solution...

    thanks
    Zahid Naqvi
    zahidalinaqvi@gmail.com

    ReplyDelete
  30. This comment has been removed by the author.

    ReplyDelete
  31. Can anybody that has implemented the drag and scroll into this example post the source. I took it from the music app and the scrolling is workling, but if I try to drag an item and drop it to a position that was previously off the screen it crashes. So obviously I messed up somewhere and I cannot figure it out.

    Also when it creates the blank space to show where I was dragging from... it repeats that blank space every six items.

    ReplyDelete
  32. Building on Logan's change to allow onItemClick, I wanted to allow onItemClick, and also allow the user to start the drag from anywhere on the item, since using the icon is not always intuitive. Just a minor change to DragNDropListView's onTouchEvent (below) to hold off on setting the dragmode until the user has dragged the item far enough to know it's not just a click (which will almost always yield some move's as well). It would probably look better if you fine-tune the start condition a bit, right now it's looking for your finger to move onto an adjacent item.

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
    final int action = ev.getAction();
    final int x = (int) ev.getX();
    final int y = (int) ev.getY();

    switch (action) {
    case MotionEvent.ACTION_DOWN:
    mStartPosition = pointToPosition(x,y);
    if (mStartPosition != INVALID_POSITION) {
    int mItemPosition = mStartPosition - getFirstVisiblePosition();
    mDragPointOffset = y - getChildAt(mItemPosition).getTop();
    mDragPointOffset -= ((int)ev.getRawY()) - y;
    }
    break;
    case MotionEvent.ACTION_MOVE:
    int currentPosition = pointToPosition(x,y);
    if (!mDragMode && (currentPosition != mStartPosition)){
    mDragMode = true;
    startDrag(mStartPosition - getFirstVisiblePosition(),y);
    }
    if (mDragMode)
    drag(0,y);// replace 0 with x if desired
    break;
    case MotionEvent.ACTION_CANCEL:
    case MotionEvent.ACTION_UP:
    default:
    if (mDragMode){
    mDragMode = false;
    mEndPosition = pointToPosition(x,y);
    stopDrag(mStartPosition - getFirstVisiblePosition());
    if (mDropListener != null && mStartPosition != INVALID_POSITION && mEndPosition != INVALID_POSITION)
    mDropListener.onDrop(mStartPosition, mEndPosition);
    }
    break;
    }

    if (!mDragMode)
    return super.onTouchEvent(ev);

    return true;
    }

    ReplyDelete
  33. Thank you for the example, very demonstrative and understandable.

    ReplyDelete
  34. @KZD76 Thank you I hope to have some time to create some more little projects like this.

    ReplyDelete
  35. @Eric Harlow
    Hello Eric! I made some changes in your code (deleting from list, monitoring change event). Where can I publish it for you (if interested)?

    ReplyDelete
  36. @KZD76
    I just pushed a repository on github that I hope to use when I start blogging again. If you can put it there. I will definitely look it over. TICEWidgets

    ReplyDelete
  37. @Eric Harlow Hi! I just sent you a pull message.

    ReplyDelete
  38. Nice and easy way to drag and drop in list view.
    Can you please suggest a way to scroll the list while dragging an item.

    Thanks,
    T

    ReplyDelete
  39. @Viraj Mody

    Could you please post your modified version of the code? I am trying to do scrolling of list while dragging an item...I don't have much experience with touch events.

    ReplyDelete
  40. First off, this code is super helpful! I am in the process of writing my first app, so this question may be a little silly. I am loading the content of the list, then allowing the user modify the order, and then updating the list. When I come back to the same page on my app, I know see the list displayed twice: first in the new order and then in the original order. I am guessing that I need to clear the list view some how or possibly make use of onPause or onResume.

    The flow goes:
    Main Page: Press -> "EditLineup"
    -- Display DragNDropPage with starting lineup --
    DragNDrop: Modify Lineup, then press "Save"
    -- Display Main Page --
    Main Page: Press -> "EditLineup"
    -- Display DragNDropPage with new lineup and starting lineup --

    Any help you could provide would be very helpful.

    -----------------
    Code snipit:

    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.dragndroplistview);

    setListAdapter(new DragNDropAdapter(this, new int[]{R.layout.dragitem}, new int[]{R.id.TextView01},
    Lineup.getPlayersNumbersAndNames()));
    listView = getListView();

    if (listView instanceof DragNDropListView) {
    ((DragNDropListView) listView).setDropListener(mDropListener);
    ((DragNDropListView) listView).setRemoveListener(mRemoveListener);
    ((DragNDropListView) listView).setDragListener(mDragListener);
    }

    Button save = (Button) findViewById(R.id.dragNdropList_save);
    save.setOnClickListener(new View.OnClickListener() {
    public void onClick(View v) {

    //Loop over all of the items in the list
    // and save the current order of the list back into the Lineup
    List tempLineup = new ArrayList(listView.getCount());
    for(int i = 0; i < listView.getCount(); i++) {
    tempLineup.add(listView.getItemAtPosition(i).toString());
    }
    Lineup.updateLineup(tempLineup);

    //Go back to home screen
    Intent myIntent = new Intent(v.getContext(), SBScorekeeperMain.class);
    startActivityForResult(myIntent, 0);
    }
    });
    }

    ReplyDelete
  41. Nevermind, I found that there is a bug somewhere in my updateLineup function such that it is storing the names twice.

    ReplyDelete
  42. Phenomonal work! I have been searching around for a good drag and drop listview to use and you have the best model yet! Everyone elses I have tried has been buggy as hell

    ReplyDelete
  43. Superb example! Keep up the good work. Thanks !!!

    ReplyDelete
  44. Really great work. What would be a great extension to this would be to use an ExpandableListView and be able to re-arrange the sub items. Does that sound doable?

    Sam

    ReplyDelete
  45. Thanks, it's one of the best tutorial.

    i like this site tutorials very much.
    but can u confirm me how to handle this one by using extends Activity .

    ReplyDelete
  46. @Naveen I am not entirely sure what you are asking. Are you saying that you don't want to use the DragNDropListActivity class instead you want to have a DragNDropActivity class that is just an Activity not a ListActivity. Does my older article Experience - Configuring Android ListView help?

    ReplyDelete
  47. This comment has been removed by the author.

    ReplyDelete
  48. How can I change background color used during dragging?

    ReplyDelete
  49. I'm tryng to work this with more views. You drag an list item, and drop on a textview! any good idea of how to make this task?

    ReplyDelete
  50. Thanks a lot, excellent example, helped me very much. But I still have a question: it is possible to create two lists in such a way that I can drag and drop between those lists using your code?

    Thanks.

    ReplyDelete
  51. Thank you for the useful example code, Eric. I've refactored it into a simpler form and templated it for arbitrary row data types. You will find here: http://www.superliminal.com/sources/SortableList.zip Just sub-class from the SortableListActivity class and implement the simple abstract methods. There's also a simple example class for String data.

    -Melinda Green
    melinda@superliminal.com

    ReplyDelete
  52. @cutelyaware I looked at your modifications. I like the templated adapter. I don't know why I don't use something like that more often. Also thanks for the attribution in the source code. I appreciate that.

    ReplyDelete
  53. Hi eric ,,
    i Am facing problem when i add a lot of items in listview and then when i try to rearrange i am not able to drag and drop to the items which are below

    ReplyDelete
  54. Melinda and Eric, thanks for great code.
    I've added two features to make the list real usable for drag'n'drop. The code is here: http://thomas.ahle.dk/SortedList.tar.gz

    I've implemented a "drop here" token, to make it more clear where you are going to drop, fixed a couple of bugs, and made it possible to drag to the bottom of the list to scroll it.

    I hope it is as useful to you, as your work was to me.
    Eric, perhaps you should post an update to the top of your site, so people coming in from StackOverflow or similar won't miss the updated solutions.

    ReplyDelete
  55. @Thomas DA

    Hi Thomas,

    There is a problem with the link, would you mind fixing it?

    ReplyDelete
  56. @Thomas DA I am willing to post links in the article. And I enjoy the comments with code contributions. I tried to follow your link but got a 404 error. If you could repost it or email it to me. I will try to post it.

    ReplyDelete
  57. I've completed the code to drag and drop, with the 'Scrolling' ability:
    download the 'DragNDropListView' class to replace in the project, here:

    http://www.filehosting.org/file/details/258354/DragNDropListView.java

    ReplyDelete
  58. @jano59

    i forgot:

    to use the 'smoothScrollToPosition() ' function, you have to set the Android Properties of your project to Android 2.2
    see:
    http://imageshack.us/photo/my-images/690/android22.png/

    ReplyDelete
  59. @jano59

    Great! But it "Force Closes" when you try to drop an item in a position that you have reached through scrolling.

    The fix:

    private void startDrag(int itemIndex, int y) {
    stopDrag(itemIndex);
    View item = getChildAt(itemIndex);
    draggedView = item;
    [...]



    private void stopDrag(int itemIndex) {
    if (mDragView != null) {
    if (mDragListener != null) {
    Log.e("INDEX: " + itemIndex);
    mDragListener.onStopDrag(draggedView);
    [...]



    Thank you all for your code, it's being very useful to me.

    ReplyDelete
  60. @jano59

    When I replace the DragNDropListView with the one in http://www.filehosting.org/file/details/258354/DragNDropListView.java,

    drop doesn't change anything anymore.
    The list is still the same.
    Do I miss something?

    ReplyDelete
  61. @Atomic

    I've checked it again and it works on my NexusOne and the eclipse'avd, without any fix.
    Proposing the upload of only one class is surely a mistake, i've surely modified more than that...i can't remember.

    here is the entire project with the scrolling ability:
    http://www.filehosting.org/file/details/261962/DragNDrop.rar

    ReplyDelete
  62. Atomic, in your project, does your adapter 'addItem()' via a doInBackground(String... params)
    in a AsyncTask thread?

    if you use multi-thread process like this to publish a progress bar, for exemple, be aware to 'notifyDataSetChanged' by a Handler defined in your main ListActivity process in the function 'public void insertItem(int to, Object o)'...

    ReplyDelete
  63. @jano59

    I haven't integrated it yet and test only with the example Activity provided.

    ReplyDelete
  64. This comment has been removed by the author.

    ReplyDelete
  65. here, the version of an automatic update when moving an item, with the scrolling ability.

    http://www.filehosting.org/file/details/263887/DragNDrop.rar

    Ps: there is the '.apk' file in the bin folder if you just want to give a glance...

    ReplyDelete
  66. @Logan

    Hello, could you please post your example somewhere for the notifyDataSetChanged() please ? Thanks :)

    ReplyDelete
  67. This comment has been removed by the author.

    ReplyDelete
  68. This comment has been removed by the author.

    ReplyDelete
  69. @jano59
    No thanks... That's done ! I've changed ArrayList to ArrayAdapter and all worked fine :)

    ReplyDelete
  70. I've extended this custom DragAndDropListView to a custom DragAndDrop ExpendableListView.
    It tried to stay as close as possible to the former code.
    I've just introduced my own way to use a holder in the BaseExpandableListAdapter since i've had to use two differents customViews,one for a group items, and one for child items.

    Note that you have to expand yourself a non expanded group before dropping a child inside.
    Note also that the code is not optimized to keep it a little more readable.


    Download here:
    https://sites.google.com/site/pharmaciefleury/folder/expDragAndDropP.1.0.rar

    ReplyDelete
  71. Very nice tutorial , I tried to make it work for preferences activity but I have and I have problems with cast exception please help me with this http://stackoverflow.com/questions/7582040/casting-issue-with-listview

    ReplyDelete
  72. @jano59
    I downloaded your example. Good! It works.
    I found a small bug that if app would crash if the start drag point is coincidentally on the line between items. The fix is pretty simple.
    Just disable mDragMode if position is invalid.

    switch (action) {
    case MotionEvent.ACTION_DOWN:
    mStartPosition = pointToPosition(x,y);
    if (mStartPosition != INVALID_POSITION) {
    .......
    }else
    mDragMode=false;

    ReplyDelete
  73. Thanks a lot for an easy, well explained, and working code !

    ReplyDelete
  74. @jano59

    The link seems to be broken, do you have another link to get the code from?

    Thanks in advance!!

    ReplyDelete
  75. Hi,

    is there any chance that you publish the sources under a GPL license?

    ReplyDelete
  76. @Alb my code is licensed under the Apache License. Is there a particular reason why you would need GPL over Apache?

    ReplyDelete
  77. @Eric Harlow

    Apache 2 and GPL 2 are not compatible [1]. As you are the owner of the sources you can distribute then under a dual license (for example), so anybody using a GPL2 license can import your code.

    It will be great for me :) (and sure for others)

    What do you think?

    [1] http://www.gnu.org/licenses/license-list.html#apache2

    ReplyDelete
  78. @Alb
    I was just trying to understand why you needed the GPL license. I think I figured it out with the Apache 2.0 and GPL 2.0 incompatibilities.

    Yes, I am willing to dual license this code. Although I think I will do it on a per case instance. My email is eric dot b dot harlow at gmail let me know where to send a GPL 2.0 licensed copy of the same code that is linked to this article.

    Hope this is helpful.

    ReplyDelete
  79. @jano59

    I've added a feature to the simple (non-expandable) list that you posted a while back: The ability to enable or disable dragging.

    I've made the following changes to DragNDropListView:

    Add these lines anywhere:


    boolean mDraggingAllowed = true;
    public void setDraggingAllowed(boolean draggingAllowed) {
    this.mDraggingAllowed = draggingAllowed;
    }

    public boolean isDraggingAllowed() {
    return this.mDraggingAllowed;
    }

    Change the following lines in onTouchEvent:

    if (action == MotionEvent.ACTION_DOWN && x < this.getWidth()/4) {
    mDragMode = true;
    }

    to:

    if (action == MotionEvent.ACTION_DOWN && x < this.getWidth()/4 && mDraggingAllowed) {
    mDragMode = true;
    }


    Sorry about just posting the changes; I don't have a server on which to put the full source.

    Thanks, everybody, for the good work. This has been a huge help to my project team.

    ReplyDelete
  80. G8 Tutorial ,

    Please confirm me one think here , when we have lot of items in a list-view dragging top item to bottom then scroll-view not working or when dragging bottom to top then same cases dragging works but scrolling not work of that list adapter how to scroll that one , if one screen size item available then no issue, but more than one page data items then scroll not works give me way to handle that issue.

    ReplyDelete
  81. Please someone reply me , when dragging item then i want my scrollview work...How to handle that cases here

    ReplyDelete
  82. Hello Greg,

    Please help me,

    I am facing same issue , i want to scroll list when dragging and dropping item on list here scroll not work please guide line me how to handle scroll here

    ReplyDelete
  83. i don't understand: there is a link of a version with the scrolling ability, among the posts upside.
    It works (i tried it with 250 items).
    Try it:

    http://www.filehosting.org/file/details/263887/DragNDrop.rar

    ReplyDelete
  84. Hello Greg,

    Thanks very much for sharing link.

    I have downloaded this rar file and play app in mobile same issue here suppose i have 10 items in a list, i want darg 10 th item on position of 1st item dragging works but scroll to move bottom to top is not working dragging time same for Top to bottom dragging scroll not works so facing issue for replace that particular item on that index .

    How to resolve that issue , i want when dragging and dropping item then same scroll move with that item movement .

    Regards
    Naveen Kumar

    ReplyDelete
  85. Hello Greg,

    Thanks very much it's working for 2.2 or 2.2+ version but

    Here with 2.1 emulator version this method smoothScrollToPosition not working, when i am using emulator version 2.2 then it's work fine, Please confirm me how to resolve this issue:



    Regards,
    Naveen

    ReplyDelete
  86. Hello Greg,

    When i am using this code

    private void scrollList(int y) {
    resetScrollBounds(y);

    int height = getHeight();
    int speed = 0;
    if (y > mLowerBound) {
    // scroll the list up a bit
    speed = y > (height + mLowerBound) / 2 ? 16 : 4;
    } else if (y < mUpperBound) {
    // scroll the list down a bit
    speed = y < mUpperBound / 2 ? -16 : -4;
    }
    if (speed != 0) {
    int ref = pointToPosition(0, height / 2);
    if (ref == AdapterView.INVALID_POSITION) {
    //we hit a divider or an invisible view, check somewhere else
    ref = pointToPosition(0, height / 2 + getDividerHeight() + 64);
    }
    View v = getChildAt(ref - getFirstVisiblePosition());
    if (v != null) {
    int pos = v.getTop();
    setSelectionFromTop(ref, pos - speed);
    }
    }
    }
    private void resetScrollBounds(int y) {
    int height = getHeight();
    if (y >= height / 3) {
    mUpperBound = height / 3;
    }
    if (y <= height * 2 / 3) {
    mLowerBound = height * 2 / 3;
    }
    }

    and calling on

    case MotionEvent.ACTION_MOVE:
    drag(0,y);// replace 0 with x if desired

    //=================
    scrollList(y);

    //================
    break;

    then scroll works sometime but some time getting blank item and exceptions , Please help me or give me guide line how to run shared code for all emulator

    Regards,
    Naveen Shrivastva

    ReplyDelete
  87. Here

    case MotionEvent.ACTION_MOVE:
    drag(0,y);// replace 0 with x if desired
    int mCurrentPosition=pointToPosition(x,y);
    mDragListener.onDrag(x, y, this); //for convenience

    if(mCurrentPosition>0){
    ///////////////////SCROLLING AREA
    if((mCurrentPosition==getFirstVisiblePosition())){
    try{this.smoothScrollToPosition (mCurrentPosition-1);
    mDragListener.onStopDrag(getChildAt(mItemPosition)); }catch(Exception e){};}
    if(mCurrentPosition==getLastVisiblePosition()&&(mCurrentPosition<this.getCount())){
    try{this.smoothScrollToPosition (mCurrentPosition+1);
    mDragListener.onStopDrag(getChildAt(mItemPosition));}catch(Exception e){};}
    /////////////////////SLIDING AREA
    if(mCurrentPosition!=mItemPosition){
    mDropListener.onDrop( mStartPosition,mCurrentPosition);
    mDragListener.onStopDrag(getChildAt(mItemPosition));
    mItemPosition=mCurrentPosition;mStartPosition=mItemPosition;}
    }
    break;


    Here 2.2 lower emulator is not able to recolonization for this.smoothScrollToPosition(pos)---method

    How to resolve this issue on lower version android emulator

    ReplyDelete
  88. @Naveen Shrivastva


    for android 1.5 may be this works: i don't know i can't bear waiting the launch in the AVD simulator (15minutes).
    i removed the 'smoothScrollToPosition' function, and create a listener to use the 'setSelection' function.
    try it...

    DragAndDropWithScrollingAbilityInAndroid 1.5

    ReplyDelete
  89. Hello Greg,

    Thanks very much by heart..

    changing method "this.smoothScrollToPosition(pos) to
    setSelection(Pos) " now it's working fine, now i am able to drag and drop on any emulator version .

    Regards,
    Naveen Kumar

    ReplyDelete
  90. hi, all

    i have 2 activity.
    (1)in activity A onCreate(), i fill all the data to ArrayList AL1, then inflate each item in the ArrayList into the screen.
    (2) when i click a button on activity A, it goes to Activity B, in B i use exactly the same ArrayList in A to inflate ListView, then i drag and drop the ListView item in B to rearrange the order.
    (3) now i want click a button in B to send back the "changed order" to A and display on the screen. how can i do it? thanks in advance.

    ReplyDelete
  91. jano59, hi can you upload again your DragAndDropWithScrollingAbilityInAndroid.rar, i need to download it.

    ReplyDelete
  92. hello...I am adding two DragNDropListView list views in ma example when i try to do that nothing is displayed the list view becomes blank.Can you please help me out on this?can i add two instance of DragNDropListView in a same activity?

    ReplyDelete
  93. aniket, i think that this bug is healthy for you, let me explain.
    First if you look at the object 'DragNDropListView' you can see that this a selfish one, justified here by the purpose of the example, to simplify things.
    for instance, look at is xml declaration id:
    android:id="@+id/android:list"
    it monopolizes a non replicable id,because it is a ListActivity at the start, that uses this listview. So if you use a xml way to instantiate your multiple DragNDropListViews => bugs somewhere in your road...
    Second, how will you DragNDrop with an object that manages just its own at the drop time...

    you have to start from an Activity class, use a Inflater to inflates a sort of MainLayout, use a Inflater to inflates your two or three or more ListViews and append them to it, and manage your OnDrag or OnMove event at the level of this Layout level.
    if it is healthy, it is because this selfishness will block when you'll want to drag from one listView and drop in the another, i think, in any case...sorry...
    you need to manage the event at this upper level, the same level that avoids this bug of instantiations, in fact.

    Maybe i'm wrong, i'm just a hobbyist, and i'm very often wrong...

    one more thing... when you'll want to drag from one listView and drop in the another...
    don't forget that:you'll need a function that verify where you drop, there is no available function in android, that looks for you what is below your moving itemView, to tell you which ListView is your destination ListView... To do that, take the position (x,y) and compare it to the coordinates top, bottom, left, right of the visible rect of each ListViews. So list them first, and verify that at each onMove events.

    ReplyDelete
  94. Does anyone have a copy of the method implementation, from Jano59's smooth scrolling example:

    smoothScrollToPosition(mCurrentPosition-1); // android 2.2

    I've downloaded the version for 1.5, and it has calls to the method commented out, and I'm trying to make the code smart enough to call the smooth scrolling if the API level is high enough, but I don't have the method implementation, and neither does Jano59.

    PS, in the original sample, Eric is saving the DrawingCacheBackgroundColor in the onStartDrag method, and setting the list item's background color to this in the onStopDrag. The default color for a list item's view is Transparent, if you set the color to something other than that, it will prevent the list item from showing the Selected, Focused and Pressed states. In onStopDrag, just set the view's background color to Color.TRANSPARENT

    Cheers!

    ReplyDelete
  95. found a copy on an another PC, this morning:

    http://www.filehosting.org/file/details/299207/DragAndDropWithScrollingAbilityInAndroid_1.5.rar

    ReplyDelete
  96. Hi Eric,

    Thanks for the article and simplified drag-n-drop utility!

    I have customized it such that user can provide the dragger element, for more info and updated source checkout -
    http://shravanmahankali.wordpress.com/2012/01/12/android-drag-n-drop-list-view/

    ReplyDelete
  97. Has android's drag and drop framework completely replaced the need for this article? Thoughts?

    ReplyDelete
  98. i have got the code from here
    http://ericharlow.blogspot.com/2010/10/experience-android-drag-and-drop-list.html

    it's very useful to me , but i have questions, how do i restore the new listview?

    i mean first the listview is like this

    a
    b
    c

    after drag and drop

    c
    b
    a

    but if i quit this app and then start it later , it will still be -> a b c

    i have some idea to use sql to save the listview id , so i can create table

    with id 1 2 3 which with content a b c in database , and then call to listview , so i can use the above code to drag , after i drag listview become c b a ,but how to save the new sequences in database like id 1 2 3 with c b a ?

    thanks for replying

    ReplyDelete
    Replies
    1. You said "but if i quit this app and then start it later , it will still be -> a b c".

      This leads me to believe your adapter is not being updated. I assume you update the views in a DragListener. I update the adapter backing the list in a DropListener. My adapter is a CursorAdapter and is backed by a SQL database, so it is possible to do what you are thinking. Hope it turns out well, and Best of Luck.

      Delete
  99. @Eric As you mentioned it uses Apache 2.0 licensing. I tried to learn if i can use the code under Apache 2.0 in commerical product but i'm not sure about this. Can you please guide about this?
    I am working on application for client. Application is planed to be published on android market where user can purchase.

    ReplyDelete
    Replies
    1. Yes, Apache 2.0 licensing can be used within a commercial product, after all, android is licensed under Apache 2.0. Any attribution in the application would be greatly appreciated but isn't a requirement of the licensing.

      Delete
  100. Thank you very much Eric for taking time to explain this.

    ReplyDelete
  101. i have the same problem as SnowBear, Cant get the example to rember the new list position on exit.

    //--CP--
    a
    b
    c

    after drag and drop

    c
    b
    a

    but if i quit this app and then start it later , it will still be -> a b c
    //--CP--

    I belive i have to do somthing like this in the DragNDropListActivity.java?

    private DropListener mDropListener =
    new DropListener() {
    public void onDrop(int from, int to) {
    ListAdapter adapter = getListAdapter();
    if (adapter instanceof DragNDropAdapter) {
    ((DragNDropAdapter)adapter).onDrop(from, to);
    getListView().invalidateViews();

    //Saving dragNDropList
    mNewPositions = new String[adapter.getCount()]; //Initialize your new items storage

    for(int i=0; i < adapter.getCount(); i++) {
    //Implement here your logic for save positions
    mNewPositions[i] = adapter.getItem(i).toString();
    }
    }
    }
    };

    Can someone help me getting this to work?

    ReplyDelete
  102. WOW what an incredible post!

    As a new android programmer I can't answer you if the new android's framework has fixed this problem but your code works so who cares!

    Working with your code makes me 3 questions:
    -Is it possible to know how it was fixed the bug that said Viraj Mody? Because I tried all links posted but almost all has been deleted :(.

    -Also I would like to know if you know how to change style to the textview only for some rows. I was thinking in having to diferents layer row but the result isn't correct...

    -Finally, If add the drag option for all row as greg said android doens't roll the list. How can I implement both things?

    Well thanks again. Because I have asked a lot of questions I let you a modification for your list providing from the list that I was using:
    http://techdroid.kbeanie.com/2009/07/custom-listview-for-android.html

    I have added an imagebutton in the row called pr1 for deleting the row just as the list before I was using.

    For doing that in DragNDropAdapter.java in getview I've added:

    (...)
    holder.text = (TextView) convertView.findViewById(mIds[0]);
    holder.del = (ImageButton) convertView.findViewById(R.id.pr1);
    (...)

    holder.text.setText(mContent.get(position));
    holder.del.setFocusableInTouchMode(false);
    holder.del.setFocusable(false);
    holder.del.setOnClickListener(this);
    holder.del.setTag(mContent.get(position));

    Class viewholder now it's:
    static class ViewHolder {
    TextView text;
    ImageButton del;
    }

    also add this new method:

    @Override
    public void onClick(View view) {
    mContent.remove(view.getTag());
    notifyDataSetChanged();

    }

    and implement OnClickListener to the baseadaptor.

    ReplyDelete
  103. Question 1:
    Jano59 files but is not as smooth as would like to be and margins are wrong.

    Question 3:
    private static long lastTouchTime = -1;

    and inside onTouchEvent replace:

    if (action == MotionEvent.ACTION_DOWN) {
    if (System.currentTimeMillis() - lastTouchTime < 750) {
    mDragMode = true;
    }
    lastTouchTime = System.currentTimeMillis();
    }

    ReplyDelete
  104. you cheated (a little). instead of using x < this.getWidth()/4, it would be better to do x < ImageView01.getRightEdge(); (when handling the touch event, and my function call may be off a little from the actual function's name)

    this makes sure that the user actually dragged the button, not some area on the left fourth of the screen.

    Great example though, this helped a lot.

    ReplyDelete
  105. Awesome work! I have a question though. In my ListActivity, I am trying to use the registerForContextMenu(listview) and I have a method


    @Override
    public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
    AdapterView.AdapterContextMenuInfo info = null;
    try {
    info = (AdapterView.AdapterContextMenuInfo) menuInfo;
    int position = info.position;
    @SuppressWarnings("unchecked")
    ArrayAdapter adapter = (ArrayAdapter)getListAdapter();
    selectedPageName = adapter.getItem(position);
    menu.add(ContextMenu.NONE, ContextMenu.NONE, ContextMenu.NONE, "Delete");
    } catch (ClassCastException e) {
    Log.e(MY_DEBUG_TAG, "bad menuInfo", e);
    return;
    }
    }

    But the context menu doesn't come up. I am using the same code on other ListActities I have and it works on those, so I am wondering if there is something unique about this list such that context menus won't work???

    ReplyDelete
    Replies
    1. I was able to get around this problem by implementing the onCreateContextMenu and onClickMenuItem methods for each row view as follows:

      // Register context menu handling here because registerForContextMenu doesn't seem to work at the
      // ListView level with the DragNDrop implementation
      textView.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
      @Override
      public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
      activity.onCreateContextMenu(menu, v, menuInfo) {
      menu.add(0, v.getId(), 0, "Delete");
      menu.getItem(0).setOnMenuItemClickListener(new OnMenuItemClickListener() {

      @Override
      public boolean onMenuItemClick(MenuItem item) {
      delete(position);
      notifyDataSetChanged();
      return true;
      }
      });
      }
      });

      Delete
    2. I mean I added this code inside the getView(...) method of the list adapter.

      Delete
  106. Hello,
    I'm using this code for my listView (which is composed of an EditText and a Checkbox) and for some reason, I'm not able to get the ACTION_DOWN event.
    While debugging, I do get 2 ACTION_MOVE events followed by an ACTION_UP event (when my finger scrolls a bit down on an item) but the ACTION_DOWN event isn't registered.
    Can someone think of a reason for this to happen?

    * Thanks a lot for posting this code. It's a great help.

    ReplyDelete
    Replies
    1. A much more likely case is your EditText which is a TextView is consuming the event in it's onKeyDown() and returning true to stop it from propagating up to your listView.

      Delete
  107. This may be a long shot, but here is an idea. In your AndroidManifest.xml Do you happen to set a min sdk and/or target sdk like this . I wrote this back when android 1.6 was the most popular sdk and I had difficulties handling differences btw pre and post 2.0 version of the sdk.

    ReplyDelete
    Replies
    1. uses-sdk android:targetSdkVersion="8" android:minSdkVersion="8"

      Delete
    2. Yes, I am using SDK 13:
      uses-sdk android:minSdkVersion="13" /

      Do you think I can still use your library in this case?

      Delete
    3. I don't see any reason why it shouldn't work with SDK 13 although I have never tested it myself. I am still guessing a ui component is consuming your ACTION_DOWN event.

      Delete
    4. I do have an OnKeyListener defined for my EditText but it always returns false for ACTION_DOWN events:

      viewHolder.text.setOnKeyListener(new OnKeyListener() {

      public boolean onKey(View v, int keyCode, KeyEvent keyEvent) {
      EditText et = (EditText) viewHolder.text;
      TodoListItem item = (TodoListItem) viewHolder.text.getTag();
      if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
      return false;
      }
      int index = todoList.indexOf(item);
      int cursor = et.getSelectionStart();
      String curItemStr = et.getText().toString();

      switch (keyCode) {
      case KeyEvent.KEYCODE_ENTER:
      if (cursor != curItemStr.length()) {
      item.setString(
      et.getText().toString()
      .substring(0, cursor - 1), 0);
      }
      insert(new TodoListItem(et.getText().toString()
      .substring(cursor, curItemStr.length()), false,
      curTask.getId()), index + 1);
      tasksLayout.refreshTasksViews();
      return true;
      case KeyEvent.KEYCODE_DEL:
      if (curItemStr.isEmpty()) {
      remove(item);

      if (index != 0) {
      EditText etUpper = (EditText) getView(index - 1,
      null, null).findViewById(R.id.editText);
      etUpper.requestFocus();
      etUpper.setInputType(0);
      }

      tasksLayout.refreshTasksViews();
      if (todoList.size() == 0) {
      emptyListTextView.setVisibility(View.VISIBLE);
      }
      return true;
      }
      break;

      default:
      break;
      }

      return false;
      }
      });

      Delete
    5. Hi again,
      After getting a hint from NeTeInStEiN in StackOverflow (link below), I managed to get it to work.
      What needed to be done is to implement the onInterceptTouchEvent() to return super.onInterceptTouchEvent().

      http://stackoverflow.com/questions/9773855/android-listview-ontouchevent-doesnt-give-action-down/10006097#10006097

      Delete
  108. Thank you! Got it going with little fuss (the manifest omission wasn't a problem). Good work--can't wait to dive into the code.

    ReplyDelete
  109. Another question,
    Now I can dragNdrop, but the dragView isn't shown on the list, but rather on another part of the screen (left from the listView). It seems the y coordinates are right but the x coordinates are all shifted.
    Any idea why this might happen?

    Thanks a lot,
    Yoel

    ReplyDelete
  110. Nice post!

    Could someone to post a new link to download DragAndDropWithScrollingAbilityInAndroid_1.5.rar?
    Thanks.

    ReplyDelete
  111. Hi Eric. This is some great stuff, and obviously has helped a ton o people. Unfortunately, I learned of your project too late into my own implementation of a drag-sort ListView. I handle some features that yours doesn't, so I'm thinking collaboration possibilities. I'd love for you to try mine out: https://github.com/bauerca/drag-sort-listview. There are a bunch of demos that can be up and running quite quickly.

    I do not think the Android Drag/Drop framework usurps a good Drag/Drop ListView (DDLV) implementation because the framework does not alleviate the complicated (in my experience) logic in a DDLV. That said, a new/updated DDLV should probably use the framework for some key features like drawing the floating/dragging View and grabbing drag events. The difficulties within onDrag callbacks in the framework will be the same as they are in the onTouchEvent method we use :)

    ReplyDelete
  112. Hi folks,

    Is there a new method with Android Drag/Drop framework to implement a Draggable List view (for reordering of items within the list) or is it best to keep the implementation the author provides?

    ReplyDelete
  113. Just wanted to thank you! Your example helped me learn quite a bit. I was able to extend your design for my needs.

    Thanks again.

    ReplyDelete
  114. This comment has been removed by the author.

    ReplyDelete
  115. Thanks! How can I create the blank space to show where I am dragging from ??

    ReplyDelete
  116. Thanks! How can I create the blank space to show where I am dragging from ??

    ReplyDelete
  117. Does anyone have a working download link for the implementation that supports scrolling? filehosting links die way too fast. None of the links is working.

    Thanks

    ReplyDelete
  118. This is great example thank you for sharing, but I want the listview in the sections (like to add headers in betn) and dont want one sections List Item to be dragged to other sections. How Would I achieve this functionality by using this code? Anyone please help me.
    Thank you.

    ReplyDelete
  119. Can Anybody please solve my above problem??

    ReplyDelete
  120. Also there is a bug in the code, When I drag drop items contineously the list item which was dragged get disappered suddenly. What could be the problem??

    ReplyDelete
  121. links:
    https://sites.google.com/site/pharmaciefleury/folder/DragAndDropWithScrollingAbilityInAndroid_1.5.rar

    and

    https://sites.google.com/site/pharmaciefleury/folder/DragNDropWithScrollingAbility.rar

    Maybe it still interests someone...
    but i've seen some news recently on the site android developers:

    public final boolean startDrag (ClipData data, View.DragShadowBuilder shadowBuilder, Object myLocalState, int flags)
    Since: API Level 11

    and this:
    http://developer.android.com/guide/topics/ui/drag-drop.html

    ReplyDelete
  122. Hi! Your project is very useful and I want to thank you. Here is an example of what I've done but on Android: http://jqueryui.com/sortable/
    My source code works right if you're scrolling, so I want to share with all of you - here's the link: http://www.4shared.com/zip/sRdXNRfr/SortableListView.html
    It's just the ListView class; If you have any questions, please ask! onChangePosition() function have to refresh the listview but before that you need to call something like that:
    public boolean dragAndDropPositionsChange(int startPos, int endPos){
    if(startPos < 0 || endPos < 0){
    return false;
    }
    Cursor cursor = getSituationsBetweenPositions(startPos, endPos);
    if(startPos < endPos){
    changePosition(cursor, -1);
    cursor.moveToLast();

    }else if(startPos > endPos){
    changePosition(cursor, 1);
    cursor.moveToFirst();
    }

    long sitId = cursor.getLong(cursor.getColumnIndex(TABLE_SITUATION.ID));
    ContentValues value = new ContentValues();
    value.put(TABLE_SITUATION.POSITION, endPos);
    db.update(TABLE_SITUATION.SQL_TABLE_NAME, value, TABLE_SITUATION.ID
    + "=" + sitId, null);

    cursor.close();
    return true;
    }

    to work properly: you need to change positions of the 2 rows. In my case I use custom SimpleCursorAdapter, so I work with cursor. If you don't work with cursor in your adapter, it should be much easier!

    ReplyDelete
  123. You need to add this after you create bitmap with the drawingcache in startDrag() method:
    item.destroyDrawingCache();
    If you don't have this in your code, next time when you drag from the same row when you dragged first, you'll see the last bitmap instead of the bitmap of the current row in your listview.

    ReplyDelete
  124. This comment has been removed by the author.

    ReplyDelete
  125. Hi, guys! Thanks to Eric for his great job, but I`ve got one bug...
    If I dragged and dropped listview item (for example, from position 4 to position 3) and after that I try drag new listview item at position 4, but in startDrag I`ve got an old reference to view (when call View item = getChildAt(itemIndex);) and I`m dragging an old view (early it was at 4 position, now it is on 3 position). Maybe somebody could help me to fix this bug?
    It is only reproduced on Android 4.1 or higher...

    ReplyDelete
  126. Alex Zezekalo:

    i think it's a common bug for those who doesn't care about listeners created in the main activity thread. Be aware to work only whith listeners, and particuliary those created in the main activity thread since only this one holds all up-to-date variables...

    if it doesn't solve your problem, it is a good advise anyway ;)

    ReplyDelete
  127. Thank you for this code, it works great! Does anyone know if the new order can be stored once the user goes back from the screen to another screen? So if it starts as Value1,Value2,Value3 and the user changes to Value2,Value1,Value3 I would store this value? Thanks.

    ReplyDelete
  128. Eric, this is a wonderful example and I thank you for it, but what I would really like is someone to explain it to me, how the various classes fit together. I'm a beginner android/java programmer and it's hard in the beginning to think in java. Maybe you don't have the time but maybe one of your readers will take it on. I am not complaining but it would have been nice if there were more comments in the code.

    Cheers,

    Jacques

    ReplyDelete
  129. This comment has been removed by the author.

    ReplyDelete
  130. Great job Eric
    I had some problem with preview image, after moving an item i got image of previous item in that place.
    Fixed setting
    item.setDrawingCacheEnabled(false);
    after getting the bitmap in startDrag
    Now i have problem with checkboxes, i think you have a fully functional example, can you post it

    ReplyDelete
  131. Good example.How do i incorporate with this list into custom list?

    ReplyDelete
  132. Helped a lot! Weird we need this constructs still in 2013, but here we are. ^^

    Thank you very much!

    ReplyDelete
  133. Great tutorial for drag and drop & most important thing very quick support.

    Thanks, all of this group membership.

    ReplyDelete
  134. Here i found a bug, what if i need to insert my list view in a scrollview inside a linearlayout with other Ui controlls.

    It will no longer move!!

    ReplyDelete
    Replies
    1. Also if i use this by setting the background of my whole list item, it is(the dragger) not getting the touch.

      Delete
  135. Hi @Eric Harlow,

    The application works simply superb.. I am currently on a project where I have to implement this functionality and when exit it should save the order by which I have changed....in the earlier version of the project my friend we able to move the text and save it with the help of a button , but now we want to implement the drag and drop... It would be a great if u help me..

    ReplyDelete
  136. Hi @Eric Harlow,
    Thanks for your post, it is very useful.But when i set target SdkVersion upper 8 in Menifest.xml then a great problem arise.currently i am using DragNDrop list under a Fragment and Google API 4.1.2, target SdkVersion 8 and it works properly.
    The problem is that in SdkVersion upper 8, when i drag any value and drop to another position, system replace it properly but when i longpressed or drag on the new replaced value then the item show the previous value instead of the replaced new one.after some drag and drop actions, when i dragged any value it always show the previous value but if i drop item then it shows the exact value.

    ReplyDelete
  137. pls reply your concern about it.

    ReplyDelete
  138. Great example and discussion thread.
    What is easy way to keep the order persistent? E.g. User changes order of list by dragging, exits and re-starts the application. He should not see the list in new order.

    ReplyDelete
    Replies
    1. Sorry for the type - *He should now see the list displayed as per new order.

      Delete
  139. Hi Eric,

    I have a great inspiration from your project and want to port your project to Xamarin Android. I'm asking if you don't mind, may I put my project on github (of course I will indicate the origin project and idea is from you)?


    Thanks!

    Jesse

    ReplyDelete
  140. Greate job and very useful example !

    I have the same problem here as helal khan:
    When I dragged & dropped an item to a new position, it was replaced properly. But after that, when I tried to drag that item again, the previous item in that position was shown. This problem could be recovered if I put the App into background and then put it back again.

    After some searchings, it seems that the views were not invalidated until the List Acvitiy paused (i.e. put into background). Does anyone have ideals on how to solve this problem ?

    This problem occurs when running the App in my Galaxy phone, but no problem in Emulator.

    Thank you very much !

    ReplyDelete
  141. => I Am Arash ! not ازش
    @EricHarlow
    I found a problem in your code that i will be thankful if you help me to solve it.
    imagine i change the position of "item 7" and "item 6" by Drag n Drop . now when i select "item 6" (which is last item now) to change its position again, its name changes to "item 7" !!
    I am really confused and any I will appreciate any help. thanks

    ReplyDelete
  142. Hi Eric,

    Great work rocks........I t will helped me a lot for my project.

    ReplyDelete
  143. Hi,
    I required one weird thing. i.e. I don't want to support/do sorting of first 3 items, it that possible by this listview ?

    ReplyDelete
  144. Nice example but only the text becomes a little bit blurry while you drag the items around. If you drop the items the text changes back to normal. How to fix this? I also don't like the use of generated colors!!

    ReplyDelete
  145. Really nice example. Nicely written as well.

    ReplyDelete