2

Right now I am using RecyclerView's ItemTouchHelper.Callback for rearranging the position of items of my recycler view.

But now what I require is a functionality of File and a Folder.

The scenario is that the file and the folder both are the item of the same recycler view. Now when I drag an item over an folder the folder should not move from its place instead it should accept the source view holder as the child of itself. And on release of an item over it the source view holder gets hidden and removed from the recycler view. While the folder remains.

I googled it a lot but was not able to find an single implementation for such behavior for Recycler View.

If any one to guide that what should i deal with, to obtain this functionality.

Thanks.

kanudo
  • 2,119
  • 1
  • 17
  • 33

1 Answers1

0

Use ItemTouchHelper.SimpleCallback. It extends ItemTouchHelper.Callback so you attach it to RecyclerView the same way.

You can use default functionality for item dragging provided by ItemTouchHelper.SimpleCallback. You can also get some notifications that will allow you to implement dropping into folder.

The following class will demonstrate changing the background color of a folder. An item will be dropped into that folder.

You should add your code for reordering and removing items (in db for example) in the described places.

class ItemDragAndDropCallback extends ItemTouchHelper.SimpleCallback {

    private final RecyclerView recyclerView;

    ItemDragAndDropCallback(RecyclerView recyclerView) {
        // Choose drag and swipe directions
        // Up and down is chosen for dragging
        // Nothing is chosen for swiping
        super(ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0);
        this.recyclerView = recyclerView;
    }

    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        int from = viewHolder.getAdapterPosition();
        int to = target.getAdapterPosition();
        // You can reorder items here
        // Reorder items only when target is not a folder
        recyclerView.getAdapter().notifyItemMoved(from, to);
        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
                folder = null;
            }
        } 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
                    )
                );
                // You can remove item from the list here and add it to the folder
                // Remember to notify RecyclerView about it
                recyclerView.getAdapter().notifyItemRemoved(viewHolder.getAdapterPosition());
            }
        }
    }

    // This method gets called a lot, so don't do any expensive operations here
    @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
                folder = null;
            }

            float itemActualPosition = viewHolder.itemView.getTop() + dY + viewHolder.itemView.getHeight() / 2;

            // Find folder under dragged item
            for (int i = 0; i < recyclerView.getChildCount(); i++) {
                View child = recyclerView.getChildAt(i);

                // Exclude dragged item from detection
                if (!child.equals(viewHolder.itemView)) {

                    // Accept folder which encloses item position
                    if (child.getTop() < itemActualPosition && itemActualPosition < child.getBottom()) {

                        folder = child;
                        // 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 over folders then the folder's background under the item will be light green. When you drop the item into a folder then its background will be dark green.