Advanced UI-Recycler View Drag and Slide

RecyclerView is powerful because it is highly customizable. Due to this advantage, most of the current projects use RecyclerView. Here we imitate the function of QQ to realize drag and slide function of RecyclerView.

Function description

Drag up and down to realize the exchange of Item
Slide left and right to delete Item
On this basis, some additional interaction functions are added.

Implementation process

First, simulate the data. You need a bean file to store the data.

public class MyMessage {
    private int logo;
    private String name;
    private String lastMsg;
    private String time;

    public MyMessage(int logo, String name, String lastMsg, String time) {
        this.logo = logo;
        this.name = name;
        this.lastMsg = lastMsg;
        this.time = time;
    }

    public int getLogo() {
        return logo;
    }

    public void setLogo(int logo) {
        this.logo = logo;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLastMsg() {
        return lastMsg;
    }

    public void setLastMsg(String lastMsg) {
        this.lastMsg = lastMsg;
    }

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }

    @Override
    public String toString() {
        return "MyMessage [logo=" + logo + ",name=" + name +
                ",lastMsg=" + lastMsg + ",time=" + time + "]";
    }
}

Then prepare the data, and use the static method to simulate the data directly.

public class DataUtils {
    public static List<MyMessage> init(){
        List<MyMessage> list = new ArrayList<MyMessage>();
        list.add(new MyMessage(R.drawable.logo, "Test No. 1", "Test content","01:34"));
        list.add(new MyMessage(R.drawable.logo, "Test No. two", "Test content","09:41"));
        list.add(new MyMessage(R.drawable.logo, "Test No. three", "Test content","11:28"));
        list.add(new MyMessage(R.drawable.logo, "Test No. four", "Test content","12:22"));
        list.add(new MyMessage(R.drawable.logo, "Test No. five", "Test content","15:25"));
        list.add(new MyMessage(R.drawable.logo, "Test No. six", "Test content","17:22"));
        list.add(new MyMessage(R.drawable.logo, "Test No. seven", "Test content","19:59"));
        list.add(new MyMessage(R.drawable.logo, "Test No. eight", "Test content","20:17"));
        list.add(new MyMessage(R.drawable.logo, "Test No. nine", "Test content","22:30"));
        list.add(new MyMessage(R.drawable.logo, "Test No. ten", "Test content","23:01"));
        return list;
    }
}

Add action refresh callback interface

public interface ItemTouchMoveListener {
    //Drag callback, drag effect refresh
    boolean onItemMove(int fromPosition,int toPosition);
    //Side slip callback, side slip effect refresh
    boolean onItemRemove(int position);
}

Add drag-and-drop callback interface

public interface StartDragListener {
    void onStartDrag(ViewHolder viewHolder);
}

Implementing adapters and overwriting the required methods

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> implements ItemTouchMoveListener{
    private StartDragListener dragListener;
    private List<MyMessage> list;

    public MyAdapter(StartDragListener dragListener, List<MyMessage> list) {
        this.list = list;
        this.dragListener = dragListener;
    }

    @Override
    public boolean onItemMove(int fromPosition, int toPosition) {
        //Data exchange
        Collections.swap(list,fromPosition,toPosition);
        //Refresh
        notifyItemMoved(fromPosition,toPosition);
        return true;
    }

    @Override
    public boolean onItemRemove(int position) {
        //Delete data
        list.remove(position);
        //Refresh interface
        notifyItemRemoved(position);
        return true;
    }

    class MyViewHolder extends RecyclerView.ViewHolder {
        private ImageView iv_logo;
        private TextView tv_name;
        private TextView tv_msg;
        private TextView tv_time;

        public MyViewHolder(View itemView) {
            super(itemView);
            iv_logo = (ImageView) itemView.findViewById(R.id.iv_logo);
            tv_name = (TextView) itemView.findViewById(R.id.tv_name);
            tv_msg = (TextView) itemView.findViewById(R.id.tv_lastMsg);
            tv_time = (TextView) itemView.findViewById(R.id.tv_time);
        }
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
        View view = layoutInflater.inflate(R.layout.item_list, parent, false);
        MyViewHolder holder = new MyViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(final MyViewHolder holder, int position) {
        MyMessage message = list.get(position);
        holder.iv_logo.setImageResource(message.getLogo());
        holder.tv_name.setText(message.getName());
        holder.tv_msg.setText(message.getLastMsg());
        holder.tv_time.setText(message.getTime());
        //Monitor logo touch events and use touch drag
        holder.iv_logo.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    //Pass it to callback
                    dragListener.onStartDrag(holder);
                }
                return false;
            }
        });
    }

    @Override
    public int getItemCount() {
        return list.size();
    }
}

Callback handling callback actions

public class MyItemTouchHelperCallback extends Callback {

    private static final String TAG = "MyItemTouchHelperCallba";
    private ItemTouchMoveListener moveListener;

    public MyItemTouchHelperCallback(ItemTouchMoveListener moveListener) {
        this.moveListener = moveListener;
    }

    //Callback first to determine the current action
    @Override
    public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) {
        //Monitor towing direction
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        //Monitoring Side Slip Direction
        int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
        int flags = makeMovementFlags(dragFlags, swipeFlags);
        return flags;
    }

    @Override
    public boolean isLongPressDragEnabled() {
        //Is dragging allowed
        return true;
    }

    //Callback while moving
    @Override
    public boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target) {
        //Call the adapter.notifyItemMoved(from,to) method to refresh the interface
        if (viewHolder.getItemViewType() != target.getItemViewType()) {
            return false;
        }
        //exchange
        boolean result = moveListener.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
        return result;
    }

    //Callback during sideslip
    @Override
    public void onSwiped(ViewHolder viewHolder, int direction) {
        //Delete data
        moveListener.onItemRemove(viewHolder.getAdapterPosition());
    }

    //Selected status
    @Override
    public void onSelectedChanged(ViewHolder viewHolder, int actionState) {
        if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
            viewHolder.itemView.setBackgroundColor(Color.BLUE);
        }
        super.onSelectedChanged(viewHolder, actionState);
    }

    //recovery
    @Override
    public void clearView(RecyclerView recyclerView, ViewHolder viewHolder) {
        viewHolder.itemView.setBackgroundColor(Color.WHITE);
        super.clearView(recyclerView, viewHolder);
    }

    //Dragging sideslip effect
    @Override
    public void onChildDraw(Canvas c, RecyclerView recyclerView, ViewHolder viewHolder,
                            float dX, float dY, int actionState, boolean isCurrentlyActive) {
        float alpha = 1 - Math.abs(dX) / viewHolder.itemView.getWidth();
		if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
            //Transparency, XY scaling
            viewHolder.itemView.setAlpha(alpha);
            //viewHolder.itemView.setScaleX(alpha);
            //viewHolder.itemView.setScaleY(alpha);
        }
        if (alpha == 0) {
            viewHolder.itemView.setAlpha(1);
			//viewHolder.itemView.setScaleX(1);
            //viewHolder.itemView.setScaleY(1);
        }
        super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
    }
}

Call in the main activity

public class MainActivity extends AppCompatActivity implements StartDragListener {

    private RecyclerView recyclerView;
    private ItemTouchHelper itemTouchHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        List<MyMessage> list = DataUtils.init();
        MyAdapter adapter = new MyAdapter(this, list);
        recyclerView.setAdapter(adapter);
        ItemTouchHelper.Callback callback = new MyItemTouchHelperCallback(adapter);
        itemTouchHelper = new ItemTouchHelper(callback);
        itemTouchHelper.attachToRecyclerView(recyclerView);
    }

    @Override
    public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
        itemTouchHelper.startDrag(viewHolder);
    }
}

So far, dragging and sideslipping of RecycleView have been completed. The following figure is to achieve the effect.

Posted by dt192 on Sat, 06 Apr 2019 20:03:32 -0700