I have a list of records in a listview that I want the user to be able to re-sort using a drag and drop method. I have seen this implemented in other apps, but I have not found a tutorial for it. It must be something that others need as well. Can anyone point me to some code for doing this?
-
1I've found this tutorial which might help [making a sortable list view](http://www.techrepublic.com/blog/australia/making-a-sortable-listview-in-android/708). I have not tested it yet but the video looks promising – Alex Sep 06 '12 at 18:11
-
@Arkde no kidding, they still haven't accepted an answer for this question, years later. – ArtOfWarfare Oct 10 '12 at 17:37
-
@ArtOfWarfare I guess one should consider that something unfortunate could have happened to the asker...disallowing further activity. – heycosmo Nov 11 '12 at 22:12
-
1@heycosmo It is possible... according to their SO profile, miannelle last visited just a month after asking the question. Also, great work on the DSLV... I made a few modifications to it to allow things like double tap to duplicate items and changing the shadow of the item as it's dragged around (my items each have their row number on them, so I made it so the row number updates can update as it's dragged.) They're kind of just hacked in, far less elegant than everything else in the class, thus why I haven't submitted the changes to GitHub. – ArtOfWarfare Nov 12 '12 at 04:07
-
https://github.com/bauerca/drag-sort-listview i am using this and is it possible to drag a ROW onLongClick of Listview ? – Achin Feb 09 '15 at 12:33
6 Answers
I have been working on this for some time now. Tough to get right, and I don't claim I do, but I'm happy with it so far. My code and several demos can be found at
Its use is very similar to the TouchInterceptor (on which the code is based), although significant implementation changes have been made.
DragSortListView has smooth and predictable scrolling while dragging and shuffling items. Item shuffles are much more consistent with the position of the dragging/floating item. Heterogeneous-height list items are supported. Drag-scrolling is customizable (I demonstrate rapid drag scrolling through a long list---not that an application comes to mind). Headers/Footers are respected. etc.?? Take a look.
![](../../users/profiles/747682.webp)
- 1,378
- 10
- 11
-
3Your solution works like a charm. Much better then others. What is license of your source code? Apache 2.0? – Dariusz Bacinski Jul 03 '12 at 07:56
-
1@heycosmo I have a few issues when creating a layout in my app using the views provided on the demo. Several namespaces error, could you please maybe do a small blogpost on how to use the code you provide? – daniel_c05 Feb 11 '13 at 18:24
-
Is there a possibility to modify code in a way that items are sorted not only on drop by while you are dragging your item above them? – Alex Semeniuk Mar 26 '13 at 13:43
-
@heycosmo Can you make your GitHub repository accessible? It seems to be offline... – sdasdadas May 12 '13 at 01:41
-
https://github.com/bauerca/drag-sort-listview i am using this and is it possible to drag a ROW onLongClick of Listview ? – Achin Feb 09 '15 at 12:33
-
8The bauerca repo is no longer maintained. This fork is more active: https://github.com/JayH5/drag-sort-listview – ecdpalma Mar 30 '15 at 20:01
-
@ecdpalma I believe your answer is a bit misleading, or at least at the moment of writing this comment. The latest commit written in the repo you provided, is October 15, while the latest commit in heycosmos repo is March 16. I have just tried today, and it works like a charm for what it was intended. And while the DragLinearLayout he provided is not a ListView, it's highly usable, simple and it works. – xarlymg89 Aug 28 '18 at 09:42
Now it's pretty easy to implement for RecyclerView
with ItemTouchHelper. Just override onMove
method from ItemTouchHelper.Callback
:
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
mMovieAdapter.swap(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
Pretty good tutorial on this can be found at medium.com : Drag and Swipe with RecyclerView
![](../../users/profiles/705635.webp)
- 5,566
- 1
- 37
- 55
Am adding this answer for the purpose of those who google about this..
There was an episode of DevBytes (ListView Cell Dragging and Rearranging) recently which explains how to do this
You can find it here also the sample code is available here.
What this code basically does is that it creates a dynamic listview
by the extension of listview
that supports cell dragging and swapping. So that you can use the DynamicListView
instead of your basic ListView
and that's it you have implemented a ListView with Drag and Drop.
![](../../users/profiles/1051147.webp)
- 8,907
- 1
- 25
- 42
-
1When using DevBytes implementation keep in mind that your adapter and DynamicListView mush share the same instance if objects array. Otherwise implementation will not work. This is not a problem for static lists but may be a challenge with Loaders – AAverin Jan 12 '14 at 09:51
-
I tried the example on a current 5.0 Android version. It has some problems now... – Torsten B Jan 07 '15 at 09:16
-
The DragListView lib does this really neat with very nice support for custom animations such as elevation animations. It is also still maintained and updated on a regular basis.
Here is how you use it:
1: Add the lib to gradle first
dependencies {
compile 'com.github.woxthebox:draglistview:1.2.1'
}
2: Add list from xml
<com.woxthebox.draglistview.DragListView
android:id="@+id/draglistview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
3: Set the drag listener
mDragListView.setDragListListener(new DragListView.DragListListener() {
@Override
public void onItemDragStarted(int position) {
}
@Override
public void onItemDragEnded(int fromPosition, int toPosition) {
}
});
4: Create an adapter overridden from DragItemAdapter
public class ItemAdapter extends DragItemAdapter<Pair<Long, String>, ItemAdapter.ViewHolder>
public ItemAdapter(ArrayList<Pair<Long, String>> list, int layoutId, int grabHandleId, boolean dragOnLongPress) {
super(dragOnLongPress);
mLayoutId = layoutId;
mGrabHandleId = grabHandleId;
setHasStableIds(true);
setItemList(list);
}
5: Implement a viewholder that extends from DragItemAdapter.ViewHolder
public class ViewHolder extends DragItemAdapter.ViewHolder {
public TextView mText;
public ViewHolder(final View itemView) {
super(itemView, mGrabHandleId);
mText = (TextView) itemView.findViewById(R.id.text);
}
@Override
public void onItemClicked(View view) {
}
@Override
public boolean onItemLongClicked(View view) {
return true;
}
}
For more detailed info go to https://github.com/woxblom/DragListView
![](../../users/profiles/225864.webp)
- 133
- 1
- 7
I found DragSortListView worked well, although getting started on it could have been easier. Here's a brief tutorial on using it in Android Studio with an in-memory list:
Add this to the
build.gradle
dependencies for your app:compile 'asia.ivity.android:drag-sort-listview:1.0' // Corresponds to release 0.6.1
Create a resource for the drag handle ID by creating or adding to
values/ids.xml
:<resources> ... possibly other resources ... <item type="id" name="drag_handle" /> </resources>
Create a layout for a list item that includes your favorite drag handle image, and assign its ID to the ID you created in step 2 (e.g.
drag_handle
).Create a DragSortListView layout, something like this:
<com.mobeta.android.dslv.DragSortListView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:dslv="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" dslv:drag_handle_id="@id/drag_handle" dslv:float_background_color="@android:color/background_light"/>
Set an
ArrayAdapter
derivative with agetView
override that renders your list item view.final ArrayAdapter<MyItem> itemAdapter = new ArrayAdapter<MyItem>(this, R.layout.my_item, R.id.my_item_name, items) { // The third parameter works around ugly Android legacy. http://stackoverflow.com/a/18529511/145173 @Override public View getView(int position, View convertView, ViewGroup parent) { View view = super.getView(position, convertView, parent); MyItem item = getItem(position); ((TextView) view.findViewById(R.id.my_item_name)).setText(item.getName()); // ... Fill in other views ... return view; } }; dragSortListView.setAdapter(itemAdapter);
Set a drop listener that rearranges the items as they are dropped.
dragSortListView.setDropListener(new DragSortListView.DropListener() { @Override public void drop(int from, int to) { MyItem movedItem = items.get(from); items.remove(from); if (from > to) --from; items.add(to, movedItem); itemAdapter.notifyDataSetChanged(); } });
![](../../users/profiles/145173.webp)
- 35,877
- 14
- 173
- 224
I recently stumbled upon this great Gist that gives a working implementation of a drag sort ListView
, with no external dependencies needed.
Basically it consists on creating your custom Adapter extending ArrayAdapter
as an inner class to the activity containing your ListView
. On this adapter one then sets an onTouchListener
to your List Items that will signal the start of the drag.
In that Gist they set the listener to a specific part of the layout of the List Item (the "handle" of the item), so one does not accidentally move it by pressing any part of it. Personally, I preferred to go with an onLongClickListener
instead, but that is up to you to decide. Here an excerpt of that part:
public class MyArrayAdapter extends ArrayAdapter<String> {
private ArrayList<String> mStrings = new ArrayList<String>();
private LayoutInflater mInflater;
private int mLayout;
//constructor, clear, remove, add, insert...
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
View view = convertView;
//inflate, etc...
final String string = mStrings.get(position);
holder.title.setText(string);
// Here the listener is set specifically to the handle of the layout
holder.handle.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
startDrag(string);
return true;
}
return false;
}
});
// change color on dragging item and other things...
return view;
}
}
This also involves adding an onTouchListener
to the ListView
, which checks if an item is being dragged, handles the swapping and invalidation, and stops the drag state. An excerpt of that part:
mListView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
if (!mSortable) { return false; }
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
break;
}
case MotionEvent.ACTION_MOVE: {
// get positions
int position = mListView.pointToPosition((int) event.getX(),
(int) event.getY());
if (position < 0) {
break;
}
// check if it's time to swap
if (position != mPosition) {
mPosition = position;
mAdapter.remove(mDragString);
mAdapter.insert(mDragString, mPosition);
}
return true;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_OUTSIDE: {
//stop drag state
stopDrag();
return true;
}
}
return false;
}
});
Finally, here is how the stopDrag
and startDrag
methods look like, which handle the enabling and disabling of the drag process:
public void startDrag(String string) {
mPosition = -1;
mSortable = true;
mDragString = string;
mAdapter.notifyDataSetChanged();
}
public void stopDrag() {
mPosition = -1;
mSortable = false;
mDragString = null;
mAdapter.notifyDataSetChanged();
}
![](../../users/profiles/3908170.webp)
- 5,985
- 3
- 33
- 52
-
While this seems to be one of the easiest implementations, it looks bad(rows just switch, there's actually zero looks), it feels bad and makes scrolling through a list that doesn't fit the screen nigh impossible (I constantly switch rows instead of scrolling). – Heinzlmaen Dec 05 '19 at 14:09