preface

Without further ado, get straight to the picture above:

RecyclerView
ItemTouchHelper

Functions:

  • Hold down theitemThe button on the left can be dragged up and downitem
  • Swipe to the right to deleteitem
  • itemDrag or side slide to have a shadow effect

Implement basic functions

Step by step learning, here we first implement the basic functions:

  • Long pressitemDrag and drop
  • Swipe to the right to delete

Layout file

Very simple, not to say, directly on the code:

activity_main.xml

<?xml version="1.0" encoding="utf-8"? >
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/main_recyclerView"
        android:scrollbars="none"
        android:background="#F2F8FC">
    </android.support.v7.widget.RecyclerView>

</LinearLayout>
Copy the code

item_list.xml

<?xml version="1.0" encoding="utf-8"? >
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="60dp"
    android:background="#ffffff">
    
    <ImageView
        android:id="@+id/item_list_menu_imageView"
        android:layout_width="30dp"
        android:layout_height="25dp"
        android:layout_marginBottom="8dp"
        android:layout_marginStart="15dp"
        android:layout_marginTop="8dp"
        android:src="@drawable/imageview_menu"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    
    <TextView
        android:id="@+id/item_list_text_textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginStart="15dp"
        android:layout_marginTop="8dp"
        android:textColor="# 000000"
        android:textSize="18sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@+id/item_list_menu_imageView"
        app:layout_constraintTop_toTopOf="parent"/>

    <android.support.v7.widget.SwitchCompat
        android:id="@+id/item_list_switchCompat"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginEnd="15dp"
        android:layout_marginTop="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        />
    
</android.support.constraint.ConstraintLayout>

Copy the code

ItemTouchHelper

Official API explanation:

This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView.

This is a tool class for RecyclerView to add sideslip delete and drag. With it, we can easily achieve the above effect. Constructor: ItemTouchHelper(ItemTouchHelper.Callback Callback) we need an ItemTouchHelper.Callback to construct an ItemTouchHelper.

ItemTouchHelper. The Callback provides an implementation class official ItemTouchHelper. SimpleCallback (), its use is very simple, but in order to get higher customization, here we don’t use it, interested friends can go to try.

A new MyItemTouchHelperCallback class inheritance ItemTouchHelper Callback, here we focus on it to one of the three methods:

  • getMovementFlags()defineitemCan drag and slide the direction.
  • onMove()itemThis method is called when you want to drag and drop.
  • onSwipeditemThis method is called when you want to sideslip left and right.

We first create a before writing MyItemTouchHelperCallback IItemTouchHelperAdapter interface, let RecyclerViewAdapter implements this interface. Used for RecyclerViewAdapter callbacks.

public interface IItemTouchHelperAdapter {
    /** ** is called when the item is moved@paramFromPosition The starting point of the item being manipulated *@paramToPosition Endpoint of the item being operated on */
    void onItemMove(int fromPosition, int toPosition);

    /** ** is called when item is sideslip@paramPosition Position of the item that is sideswiped */
    void onItemDismiss(int position);
}
Copy the code

Implement the two methods you just inherited in RecyclerViewAdapter:

  @Override
    public void onItemMove(int fromPosition, int toPosition) {
        Collections.swap(mList, fromPosition, toPosition);
        notifyItemMoved(fromPosition, toPosition);
    }

    @Override
    public void onItemDismiss(int position) {
        mList.remove(position);
        notifyItemRemoved(position);
    }
Copy the code

Then we can start to write MyItemTouchHelperCallback, comments clear, not much said.

public class MyItemTouchHelperCallback extends ItemTouchHelper.Callback {

    private IItemTouchHelperAdapter mAdapter;

    public MyItemTouchHelperCallback(IItemTouchHelperAdapter mAdapter) {
        this.mAdapter = mAdapter;
    }

    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        // Drag up and down, if you have other requirements
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        // Slide to the right, if you have other requirements
        int swipeFlags = ItemTouchHelper.RIGHT;
        return makeMovementFlags(dragFlags, swipeFlags);
    }

    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        // Notify Adapter to update data and views
        mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
        // If false is returned, dragging and dropping is not supported
        return true;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        // Notify Adapter to update data and views
        mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
    }
    
    @Override
    public boolean isItemViewSwipeEnabled(a) {
        // Whether you can slide left and right, default return true
        return true;
    }

    @Override
    public boolean isLongPressDragEnabled(a) {
        // Whether you can drag up and down by long pressing, false is returned by default
        return true; }}Copy the code

Finally, in Acivity, associate ItemTouchHelper with RecyclerView

    mItemTouchHelper = new ItemTouchHelper(new MyItemTouchHelperCallback(adapter));
    mItemTouchHelper.attachToRecyclerView(recyclerView);
Copy the code

Operation effect:

perfect

There is still a little gap between the basic effect we have achieved and the effect given at the beginning of the article, and the effect still needs to be achieved:

  • By holding down theitemThe left button can only be dragged up and down.
  • Being operated by sideslip or dragitemZ-axis height increased, there are distinct shadows.

By holding down theitemThe left button can only be dragged up and down

First modify MyItemTouchHelperCallback isLongPressDragEnabled ()

 @Override
    public boolean isLongPressDragEnabled(a) {
        // Don't drag item up and down, because we want to customize when drag is enabled
        return false;
    }
Copy the code

Next, create an OnStartDragListener interface for callbacks

public interface OnStartDragListener {
    /** * Callback ** when the View needs to be dragged@param viewHolder The holder of view to drag
     */
    void onStartDrag(RecyclerView.ViewHolder viewHolder);
}
Copy the code

Let your Activity inherit this class and implement the onStartDrag() method

@Override
    public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
        // Tell ItemTouchHelper to start dragging
        mItemTouchHelper.startDrag(viewHolder);
    }
Copy the code

In the RecyclerViewAdapter constructor, pass an instance of OnStartDragListener (that is, the Activity that implements the interface) to add event listeners to the button to the left of the Item

public class RecyclerViewAdapter extends
        RecyclerView.Adapter<RecyclerViewAdapter.ItemViewHolder> implements IItemTouchHelperAdapter {
    // constructor
    public RecyclerViewAdapter(List<ItemEntity> list, OnStartDragListener mDragListener) {
        mList = list;
        this.mDragListener = mDragListener; }...@Override
    public void onBindViewHolder(final IItemViewHolder holder, @SuppressLint("RecyclerView") final int position) {... holder.menu.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                if (motionEvent.getAction()
                        == MotionEvent.ACTION_DOWN) {
                    // Tell ItemTouchHelper to start dragging
                    mDragListener.onStartDrag(holder);
                }
                return false; }}); }... }Copy the code

Being operated by sideslip or dragitemZ-axis height increased, there are distinct shadows

To achieve this effect, we use two Callback methods provided by ItemTouchHelper.Callback:

  • onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState): whenViewHolder(i.e.item) is called when sliding or dragging.
  • clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder): whenViewHolderIs called when the slide and drag end

First create a new IItemTouchHelperViewHolder interface for callback, let RecyclerViewAdapter ViewHolder inherit it.

public interface IItemTouchHelperViewHolder {

    /** * item is selected to update the status */ during sideslip or drag
    void onItemSelected(a);

    /** * The drag and slide of item ends, and the default state */ is restored
    void onItemClear(a);
}
Copy the code

Then let ViewHolder override the above two methods:

 class ItemViewHolder extends RecyclerView.ViewHolder implements IItemTouchHelperViewHolder {
        private TextView text;
        private ImageView menu;
        private SwitchCompat switchCompat;

        ItemViewHolder(View itemView) {
            super(itemView);
            text = itemView.findViewById(R.id.item_list_text_textView);
            menu = itemView.findViewById(R.id.item_list_menu_imageView);
            switchCompat = itemView.findViewById(R.id.item_list_switchCompat);
        }

        @Override
        public void onItemSelected(a) {
            itemView.setTranslationZ(10);
        }

        @Override
        public void onItemClear(a) {
            itemView.setTranslationZ(0); }}Copy the code

Here we change the height of the itemView by setTranslationZ().

I tried to change the height of the View by using setElevation(), but it didn’t work.

  • elevationIs a static value, yesViewThe initial value on the Z axis
  • translationZIs the dynamic value, is the shift on Z

So instead of using setElevation(), we should use setTranslationZ() to change the height of the View’s Z-axis. You can try it out for yourself.

Last modified MyItemTouchHelperCallback, rewrite the above two methods, the process is simple, direct look at the code:

 @Override
    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
        if(actionState ! = ItemTouchHelper.ACTION_STATE_IDLE) {// No idle state, i.e. drag or slide state
            if (viewHolder instanceofIItemTouchHelperViewHolder) { IItemTouchHelperViewHolder itemTouchHelperViewHolder = (IItemTouchHelperViewHolder) viewHolder; itemTouchHelperViewHolder.onItemSelected(); }}super.onSelectedChanged(viewHolder, actionState);
    }

    @Override
    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        super.clearView(recyclerView, viewHolder);
        if (viewHolder instanceofIItemTouchHelperViewHolder) { IItemTouchHelperViewHolder itemTouchHelperViewHolder = (IItemTouchHelperViewHolder) viewHolder; itemTouchHelperViewHolder.onItemClear(); }}Copy the code

The last

Here is [source]

Feel free to leave me a comment in the comments section if there are any mistakes or areas that could be improved