One, a brief introduction

RecyclerView has item animation by default, for example, when adding or deleting an item, there will be an animation between items displacement, but this article is not about this!! The main character of this article is ItemTouchHelper in V7 package, which will bring magical interactive effects when combined with RecyclerView. The following is an example:

The effect is still pretty cool. There are four steps in the picture above:

  1. Hold and drag item to switch positions with other items
  2. Hold down the icon on the right of an item and drag it to switch positions with other items
  3. Left slide item becomes transparent and shrinks. When it exceeds the screen, other items are added
  4. Right slide item to become transparent and zoom out. When it exceeds the screen, other items are added

Each of these effects will be implemented below

ItemTouchHelper 2

1. Create ItemTouchHelper

MItemTouchHelper = new ItemTouchHelper(mCallback); mItemTouchHelper.attachToRecyclerView(mRv);Copy the code

This is two of the three lines of ItemTouchHelper in this example, but it doesn’t do the job. ItemTouchHelper is just a middleman that connects ItemTouchHelper.Callback to RecyclerView. The effect needs to be implemented by Callback.

2. Customize ItemTouchHelper.callback

1) Create your own Callback

After inheriting ItemTouchHelper.callback, you must implement the following three methods.

public class MyItemTouchHelperCallback extends ItemTouchHelper.Callback {

    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        return 0;
    }

    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder targetViewHolder) {
        return false;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {

    }
}
Copy the code

2) Override getMovementFlags()

GetMovementFlags () is used to determine which direction of RecyclerView operations should be controlled by ItemTouchHelper.callback.

/** * Get action flags * action flags: dragFlags and swipeFlags * dragFlags: action flags of the scrolling direction of the list (e.g. vertical list is up and down, horizontal list is left and right) * wipeFlags: Actions that are perpendicular to the scrolling direction of a list (e.g. vertical lists are left and right, Override public int getMovementFlags(RecyclerView RecyclerView, Recyclerview.viewholder ViewHolder) {// If you don't want to drag up and down, Can be dragFlags = 0 int dragFlags = ItemTouchHelper. UP | ItemTouchHelper. DOWN; / / if you don't want to slip, can be swipeFlags = 0 int swipeFlags = ItemTouchHelper. LEFT | ItemTouchHelper. RIGHT. Int flags = makeMovementFlags(dragFlags, swipeFlags); return flags; }Copy the code

Itemtouchhelper.callback Controls the upper, lower, left, and right sides of the item.

You can see that left and right works, but up and down doesn’t. RecyclerView RecyclerView RecyclerView RecyclerView RecyclerView RecyclerView itemTouchHelper.callback So, to trigger the drag up and down interaction, there must be another way to turn it on.

3) Enable the drag effect by holding down item

Override isLongPressDragEnabled() for ItemTouchHelper.callback directly.

*/ @override public Boolean isLongPressDragEnabled() {return true; }Copy the code

The default return is false, and overwriting returns true. Now let’s see how this works:

After long pressing, you can drag, but this is not very convenient. Next, you can drag by holding down the icon to the right of item.

4) Enable the drag effect by holding down the icon

The ItemTouchHelper startDrag(viewHolder) method can enable the drag effect manually. The above ItemTouchHelper instance is created in the Activity, while the icon instance is in the Adapter.

public interface ItemDragListener {
    void onStartDrags(RecyclerView.ViewHolder viewHolder);
}
Copy the code

The interface is implemented by the Activity and passed in when the Adapter is created

public class ItemTouchHelperActivity extends AppCompatActivity implements ItemDragListener { private ItemTouchHelper mItemTouchHelper; . private void setRecyclerView() { mAdapter = new ItemTouchHelperAdapter(mData, this); . } @Override public void onStartDrags(RecyclerView.ViewHolder viewHolder) { mItemTouchHelper.startDrag(viewHolder); }}Copy the code

The interface is invoked when the Adapter icon is touched

public class ItemTouchHelperAdapter extends RecyclerView.Adapter<ItemTouchHelperAdapter.ItemTouchHelperViewHolder> { private List<String> mData; private ItemDragListener mItemDragListener; public ItemTouchHelperAdapter(List<String> data, ItemDragListener itemDragListener) { mData = data; mItemDragListener = itemDragListener; }... @Override public void onBindViewHolder(final ItemTouchHelperViewHolder viewHolder, int position) { ... viewHolder.mIvDrag.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { mItemDragListener.onStartDrags(viewHolder); return false; }}); }}Copy the code

So when he makes icon on the touch, indirect calls the mItemTouchHelper. StartDrag (viewHolder), look at the effect:

3. Dive into ItemTouchHelper

Dragging item up and down and sliding item left and right are done above, but they are only animations of the current item. Let’s continue to complete the effects of interaction with other items.

1. Drag up and down to swap positions with other items

1) principle

In fact, ItemTouchHelper.Callback itself does not have the function of changing the location of two items, but RecyclerView does. We can change the location of the current item with that of another item when the item is dragged. Call notifyItemMoved() of RecyclerView to refresh the layout, and RecyclerView has its own item animation.

2) implementation

The item drag is listened on in itemTouchHelper. Callback, and the data exchange is performed on the Adapter.

public interface ItemMoveListener {
    boolean onItemMove(int fromPosition, int toPosition);
}
Copy the code

Interfaces are implemented by Adapter

public class ItemTouchHelperAdapter extends RecyclerView.Adapter<ItemTouchHelperAdapter.ItemTouchHelperViewHolder> implements ItemMoveListener{ ... @override public Boolean onItemMove(int fromPosition, int toPosition) {Override public Boolean onItemMove(int fromPosition, int toPosition) { toPosition); // update notifyItemMoved(fromPosition, toPosition); return true; }}Copy the code

The interface is passed in when itemTouchHelper.callback is created and called in onMove()

public class MyItemTouchHelperCallback extends ItemTouchHelper.Callback { ItemMoveListener mItemMoveListener; public MyItemTouchHelperCallback(ItemMoveListener itemMoveListener) { mItemMoveListener = itemMoveListener; }... /** * Trigger when item is dragged ** @param recyclerView * @param viewHolder The viewHolder of the current dragged item * @param targetViewHolder @override public Boolean onMove(RecyclerView RecyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder targetViewHolder) { return mItemMoveListener.onItemMove(viewHolder.getAdapterPosition(), targetViewHolder.getAdapterPosition()); }}Copy the code

3) Effect:

2. Other items are added when you slide out of the screen

1) principle

Similarly, delete the corresponding data when item slides out of the screen, and then call notifyItemRemoved() of RecyclerView to refresh the layout.

2) implementation

Item sliding is listened on in ItemTouchHelper.Callback, and data deletion is done on Adapter, so simply add a method to the interface above:

public interface ItemMoveListener {
    ...
    boolean onItemRemove(int position);
}
Copy the code

Interfaces are implemented by Adapter

public class ItemTouchHelperAdapter extends RecyclerView.Adapter<ItemTouchHelperAdapter.ItemTouchHelperViewHolder> implements ItemMoveListener{ ... @override public Boolean onItemRemove(int position) {//1, delete mdata. remove(position); //2, refresh notifyItemRemoved(position); return true; }}Copy the code

The interface is called in ItemTouchHelper.Callback in onSwiped()

/** * Triggered when item slips out (vertical list is slippage, / @override public void onSwiped(recyclerView.viewholder) viewHolder, int direction) { mItemMoveListener.onItemRemove(viewHolder.getAdapterPosition()); }Copy the code

3) Effect:

Now that most of the effects are in place, it’s time to work on the details.

3. Background changes during interaction

1) principle

Itemtouchhelper.callback has methods for both states: onSelectedChanged() and clearView().

2) implementation

/** * Triggered when an item is dragged or slid ** @param viewHolder * @param actionState Current item status */ @override public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { super.onSelectedChanged(viewHolder, actionState); // If (actionState! = ItemTouchHelper.ACTION_STATE_IDLE) viewHolder.itemView.setBackgroundColor(viewHolder.itemView.getContext().getResources().getColor(android.R.color.darker_g ray)); } /** * when the item interactive animation ends ** @param recyclerView * @param viewHolder */ @override public void clearView(recyclerView) recyclerView, RecyclerView.ViewHolder viewHolder) { super.clearView(recyclerView, viewHolder); viewHolder.itemView.setBackgroundColor(viewHolder.itemView.getContext().getResources().getColor(android.R.color.white));  }Copy the code

3) the effect of

4. Item gradually changes when sliding left and right

1) Analysis and implementation

In the initial picture, when the item is slid out sideways, it can be seen that the transparency of the item is gradually lightened and its height is gradually reduced. In fact, the item is animated with two attributes. In itemTouchHelper.callback, there is a method to retrieve the displacement of an item when it is dragged or slid. This is called onChildDraw().

@Override public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, Float dY, int actionState, Boolean isCurrentlyActive) {// Super.onchilddraw (c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive) // We just need to slide left and right, ActionState == ItemTouchHelper.action_state_swipe) {float value = 1 - math.abs (dX) / viewHolder.itemView.getWidth(); viewHolder.itemView.setAlpha(value); viewHolder.itemView.setScaleY(value); }}Copy the code

2) Effect (flawed)

As can be seen, item gradually becomes transparent and its height shrinks during the sliding process. However, I clearly deleted two items, and there are two more blank data in the result list. Why is that?

3) repair

The RecyclerView item (itemView) is used as an overuse of the RecyclerView item (itemView). In the previous onChildDraw() method, the itemView was set to transparent and shrink. There are only a few ItemViews in a list. When the two transparently reduced ItemViews are used again, the ratio of transparency to height is already set to 0. The solution is also simple. Set the opacity and height ratio of itemView back as follows:

/* Override public void clearView(recyclerView); /* Override public void clearView(recyclerView) recyclerView, RecyclerView.ViewHolder viewHolder) { super.clearView(recyclerView, viewHolder); . viewHolder.itemView.setAlpha(1); viewHolder.itemView.setScaleY(1); }Copy the code

4) Effect (perfect)

At this point, all of the initial interactions have been implemented.

The Demo link is attached

Github.com/GitLqr/Mate…