5

I was looking for a ListPreference in which the user can change the order of items from a list. The items would be draggable and can be re-ordered by the user.

I saw this in my custom ROM (and I'm almost sure I saw it in Cyanogenmod) for the QuickPanel. Here's a screenshot to get the idea through:

Screenshot of the "widget Button Order" in QuickPanel Settings of Sabotage ROM

I know how I can make custom ListView items and set the icon to indicate that the items are draggable, but I don't know how to make them draggable, and change the order accordingly. As for saving them in the preferences, I found this which could be implemented easily.

PS: I know Cyanogenmod is open-source, but I couldn't find the source for this particular thing :( The closest I could get was this, which should be somewhere near the other screen...

Thanks in advance for any tip about this.

UPDATE: I ended up using the files from the accepted answer, with additions and modifications. I am listing them here for further reference.

  • Use a custom Adapter (ArrayAdapter in my case), to implement the visual feedback that this item is draggable, which is an ImageView near the TextView. This is optional.

  • Set a DragListener and RemoveListener to update the list accordingly. The ListView does not do that automatically. And it depends on the Adapter you are using.

  • There was a line that casted a View to a ViewGroup, it made some errors, so I removed the cast without any issue, it was not needed. (in the onInterceptTouchEvent method).

  • Change mRemoveMode = 1; in the constructor of TouchInterceptor, or one of: FLING = 0; SLIDE = 1; TRASH = 2;. I think for TRASH, a resource should be available too.

I actually took the file not from the answer's link but from the Cyanogenmod one, which I already had, but I guess these files were the same.

These are the actual files in the project (at r12, at the time of writing):

I hope it helps somebody else :)

Community
  • 1
  • 1
jadkik94
  • 7,000
  • 2
  • 30
  • 39
  • There's no standard function for this, so you have to override onTouch and detect the touch event. Your override would probably be activated by a longClick event, otherwise you don't know if the user wants to drag an item or scroll the list. – Christine Jun 20 '12 at 16:25
  • @Christine Can't I use [OnDragListener](http://developer.android.com/reference/android/view/View.OnDragListener.html)? – jadkik94 Jun 20 '12 at 16:32
  • @jadkik94 Hi. I'm trying to implement the same thing using these files. But since it's a pretty old question, I was wondering if there's a better or rather I'd say more convenient method to implement a drag-able list has come up or not? I couldn't find any though. Will appreciate any pointers you can give.. Thanks. – Anjani Mar 17 '15 at 14:49

1 Answers1

5

There is no built-in widget to do this, but you may want take a look at the custom implementation used by the AOSP music player to allow for re-ordering of songs in playlists.

TouchInterceptor.java

That's the class which is extending ListView and is responsible for handling all of the MotionEvents and re-ordering its items, as well as detecting swipes for deleting items. You can see it implemented into an activity here in the TrackBrowserActivity.java class.

It has three interfaces you should also be aware of: DragListener, DropListener, and RemoveListener. You can use these interfaces to provide it callbacks to fire for those events, so that you can update changes made to the list order to your SavedPreferences (since the ListView will not handle that for you).

You can easily extend or modify the TouchInterceptor class to add additional functionality since the low-level stuff is all there for you.

Victor
  • 1,137
  • 1
  • 10
  • 15
  • Right, I knew I saw that somewhere else, why didn't I think of this? It's weird they don't use the drag and drop events like [in the docs](http://developer.android.com/guide/topics/ui/drag-drop.html). Anyway, I could've never done this alone. Thanks, I'll try it and get back to you. – jadkik94 Jun 20 '12 at 16:41
  • The Drag and Drop API was added in API level 11, and this implementation targets API level 8, so it was probably written before that API was completed or widely available. – Victor Jun 20 '12 at 16:44
  • That might be it. I just noticed something, are you sure the TouchInterceptor class is used in MusicPicker.java? That class is not imported/used there. – jadkik94 Jun 20 '12 at 16:49
  • Looking at `TouchInterceptor.java`'s history, I think it's used in [TrackBrowser.java](https://github.com/android/platform_packages_apps_music/blob/master/src/com/android/music/TrackBrowserActivity.java) – jadkik94 Jun 20 '12 at 16:53
  • Oops, you're right. It's not used in MusicPicker, it's actually used in [MediaPickerActivity](https://github.com/android/platform_packages_apps_music/blob/master/src/com/android/music/MediaPickerActivity.java). You can see the XML layout file MediaPickerActivity is loading [here](https://github.com/android/platform_packages_apps_music/blob/master/res/layout/media_picker_activity.xml). However, you still won't see any imports since it's just treating it as a regular ListView. – Victor Jun 20 '12 at 16:56
  • Yep, it also appears to be used in TrackBrowser as well. That's a better example, because you can see how the listeners are being used. At line 166, there's an if(mEditMode) conditional, when then casts the ListView to a TouchInterceptor and sets the appropriate callbacks for drag n' drop and removing items. – Victor Jun 20 '12 at 16:58
  • Thanks, I implemented it successfully :) I had to change some things, like resources used, and preferences used, but I got it working (almost) as it is supposed to be. – jadkik94 Jun 22 '12 at 16:12