Switching your ListView
to RecyclerView
will make things a lot easier.
You can find the whole article on Styling Android and the whole code here.
This code uses OnItemTouchListener
to detect when an item should be dragged. There is an ImageView
above the RecyclerView
with an image of the item being moved to cheaply animate it.
The OnItemTouckListener
(DragController.java
):
public class DragController implements RecyclerView.OnItemTouchListener {
private RecyclerView recyclerView;
private ImageView overlay;
private final GestureDetectorCompat gestureDetector;
private boolean isDragging = false;
public DragController(RecyclerView recyclerView, ImageView overlay) {
this.recyclerView = recyclerView;
this.overlay = overlay;
GestureDetector.SimpleOnGestureListener longClickGestureListener = new GestureDetector.SimpleOnGestureListener() {
@Override
public void onLongPress(MotionEvent e) {
super.onLongPress(e);
isDragging = true;
dragStart(e.getX(), e.getY());
}
};
this.gestureDetector = new GestureDetectorCompat(recyclerView.getContext(), longClickGestureListener);
}
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
if (isDragging) {
return true;
}
gestureDetector.onTouchEvent(e);
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
int x = (int) e.getX();
int y = (int) e.getY();
View view = recyclerView.findChildViewUnder(x, y);
if (e.getAction() == MotionEvent.ACTION_UP) {
dragEnd(view);
isDragging = false;
} else {
drag(y, view);
}
}
Starting and ending the drag (DragController.java
):
private boolean isFirst = true;
private static final int ANIMATION_DURATION = 100;
private int draggingItem = -1;
private float startY = 0f;
private Rect startBounds = null;
private void dragStart(float x, float y) {
View draggingView = recyclerView.findChildViewUnder(x, y);
View first = recyclerView.getChildAt(0);
isFirst = draggingView == first;
startY = (y - draggingView.getTop());
paintViewToOverlay(draggingView);
overlay.setTranslationY(y - startY);
draggingView.setVisibility(View.INVISIBLE);
draggingItem = recyclerView.indexOfChild(draggingView);
startBounds = new Rect(draggingView.getLeft(), draggingView.getTop(), draggingView.getRight(), draggingView.getBottom());
}
private void drag(int y, View view) {
overlay.setTranslationY(y - startY);
}
private void dragEnd(View view) {
overlay.setImageBitmap(null);
view.setVisibility(View.VISIBLE);
view.setTranslationY(overlay.getTranslationY() - view.getTop());
view.animate().translationY(0f).setDuration(ANIMATION_DURATION).start();
}
private void paintViewToOverlay(View view) {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
overlay.setImageBitmap(bitmap);
overlay.setTop(0);
}
The code is written by Mark Allison on StylingAndroid.
Edit:
But I don't know how to get the position of item when dragging is end
The answer is located in part 7 on Styling Android.
View view = recyclerView.findChildViewUnder(0, y);
And how can I disable drag on Folder and Header item? Just allow dragging File item?
You can do this by using multiple ViewTypes (file, folder & header). Then you can use getItemViewType in DragController
to start the movement only for files.
RecyclerView
withItemTouchHelper
from the support library? – RenninRecyclerView
, is it easier to do that? – KumquatItemTouchHelper
is for adding drag & drop and swipe to dismiss support toRecyclerView
. Take a look at theItemTouchHelper
docs, see if you can find an example online. I can't understand why your question isn't getting more attention, there are lots of libraries out there to do this sort of thing. – Rennin