Drag a Listview item to another item

I have a list view with different types of elements: header, folder and file:

enter image description here

Now I would like to implement a drag and drop file element and put it in a folder element and get the source and target position. I don’t want to change the target position (reorder) while dragging, like some drag list view libraries.

Is there any suggestion for a start?

+5
source share
2 answers

Switching ListView to RecyclerView will simplify the job.

You can find the whole article on Styling Android and all the code here.

This code uses OnItemTouchListener to determine when an item needs to be dragged. There is an ImageView above the RecyclerView with an image of an object being moved to bring it to life cheaply.

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 a drag and drop ( 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); } 

Code written by Mark Allison on StylingAndroid.

Edit:

But I do not know how to get the position of an element when dragging end

The answer is in part 7 on Android styling.

 View view = recyclerView.findChildViewUnder(0, y); 

And how can I turn off the drag and drop of the Folder and Title elements? Just allow drag and drop file?

You can do this using multiple ViewTypes (file, folder and title). Then you can use getItemViewType in the DragController to start the file-only move.

+1
source

Use RecyclerView and ItemTouchHelper.SimpleCallback .

You can configure it this way:

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_list); // Your layout with RecyclerView RecyclerView itemRecyclerView = findViewById(R.id.itemRecyclerView); LinearLayoutManager itemLayoutManager = new LinearLayoutManager(this); itemRecyclerView.setLayoutManager(itemLayoutManager); itemAdapter = new ItemAdapter(); // Your adapter which extends RecyclerView.Adapter itemRecyclerView.setAdapter(itemAdapter); itemRecyclerView.setHasFixedSize(true); itemDragAndDropCallback = new ItemDragAndDropCallback(this, itemRecyclerView); // Your class which extends ItemTouchHelper.SimpleCallback // It will be shown in the next code sample new ItemTouchHelper(itemDragAndDropCallback) .attachToRecyclerView(itemRecyclerView); } 

You can use the default drag and drop features provided by ItemTouchHelper.SimpleCallback . The following class will demonstrate changing the background color in a folder. The item will be deleted to this folder.

 class ItemDragAndDropCallback extends ItemTouchHelper.SimpleCallback { ItemDragAndDropCallback() { // Choose drag and swipe directions // Up and down is chosen for dragging // Right and left is chosen for swiping super(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.RIGHT | ItemTouchHelper.LEFT); } @Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { // You can reorder items here // Do nothing in your case return true; } @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { // You can react for swiping items here // Do nothing in your case } // An item will be dropped into this folder private View folder; @Override public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { super.onSelectedChanged(viewHolder, actionState); if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) { // Here you are notified that the drag operation began if (folder != null) { folder.setBackgroundResource(0); // Clear former folder background } } else if (actionState == ItemTouchHelper.ACTION_STATE_IDLE) { // Here you are notified that the last operation ended if (folder != null) { // Set folder background to a color indicating // that an item was dropped into it folder.setBackgroundColor( ContextCompat.getColor( recyclerView.getContext(), android.R.color.holo_green_dark ) ); } } } @Override public void onChildDraw( Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive ) { if (actionState == ItemTouchHelper.ACTION_STATE_DRAG && isCurrentlyActive) { // Here you are notified that the drag operation is in progress if (folder != null) { folder.setBackgroundResource(0); // Clear former folder background } float itemActualPosition = viewHolder.itemView.getTop() + dY; // Find folder under dragged item for (int i = 0; i < recyclerView.getChildCount(); i++) { folder = recyclerView.getChildAt(i); // Exclude dragged item from detection if (!folder.equals(viewHolder.itemView)) { // Accept folder which encloses item position if (folder.getTop() < itemActualPosition && itemActualPosition < folder.getBottom()) { // Set folder background to a color indicating // that an item will be dropped into it upon release folder.setBackgroundColor( ContextCompat.getColor( recyclerView.getContext(), android.R.color.holo_green_light ) ); break; } } } } super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); } } 

When you drag an item through folders, the background of the folder below the item will be light green. When you drop an item into a folder, its background will be dark green.

0
source

Source: https://habr.com/ru/post/1238774/


All Articles