RecyclerView的item拖动排序效果以及侧滑删除实现和它的ItemTouchHelper详解

说明: 
1.实现这个效果的核心类是:ItemTouchHelper和ItemTouchHelper.Callbck. 
2.mainActivity的布局就是一个recyclerview,item的布局cardview套着三个控件。

 首先看MAinActivity的代码吧

public class MainActivity extends AppCompatActivity {

    List list;
    RecyclerView recyclerView;
    MyAdapter myAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView = findViewById(R.id.ry);
        list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            list.add("我的序号是:" + i);
        }
        myAdapter = new MyAdapter(list);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setAdapter(myAdapter);
        //1.创建item helper
        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
        //2.绑定到recyclerview上面去
        itemTouchHelper.attachToRecyclerView(recyclerView);
        //3.ItemHelper的接口回调中过滤开启长按拖动,拓展其他操作
    }

    //itemHelper的回调
    ItemTouchHelper.Callback callback = new ItemTouchHelper.Callback() {
        /**
         * 官方文档的说明如下:
         * o control which actions user can take on each view, you should override getMovementFlags(RecyclerView, ViewHolder)
         * and return appropriate set of direction flags. (LEFT, RIGHT, START, END, UP, DOWN).
         * 返回我们要监控的方向,上下左右,我们做的是上下拖动,要返回都是UPDOWN
         * 关键坑爹的是下面方法返回值只有1个,也就是说只能监控一个方向。
         * 不过点入到源码里面有惊喜。源码标记方向如下:
         *  public static final int UP = 1     0001
         *  public static final int DOWN = 1 << 1; (位运算:值其实就是20010
         *  public static final int LEFT = 1 << 2   左 值是3
         *  public static final int RIGHT = 1 << 3  右 值是8
         */
        @Override
        public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
            //也就是说返回值是组合式的
            //监控左右侧滑的方法swipFlag=ItemTouchHelper.LEFT|ItemTouchHelper.RIGHT;
            int swipFlag = ItemTouchHelper.LEFT|ItemTouchHelper.RIGHT;
            //监控上下滑动的方法dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
            int dragflag = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
            //等价于:0001&0010;多点触控标记触屏手指的顺序和个数也是这样标记哦
            //makeMovementFlags (int dragFlags, int swipeFlags),看下面的解释说明
            return  makeMovementFlags(dragflag,swipFlag);
            /**
             * 备注:由getMovementFlags可以联想到setMovementFlags,不过文档么有这个方法,但是:
             * makeMovementFlags (int dragFlags, int swipeFlags)
             * Convenience method to create movement flags.便捷方法创建moveMentFlag
             * For instance, if you want to let your items be drag & dropped vertically and swiped left to be dismissed,
             * you can call this method with: makeMovementFlags(UP | DOWN, LEFT);
             * 这个recyclerview的文档写的简直完美,示例代码都弄好了!!!
             * 如果你想让item上下拖动和左边滑动删除,应该这样用: makeMovementFlags(UP | DOWN, LEFT)
             */

            //拓展一下:如果只想上下的话:makeMovementFlagsUP | DOWN, 0,标记方向的最小值1
        }

        /**
         * 官方文档的说明如下
         * If user drags an item, ItemTouchHelper will call onMove(recyclerView, dragged, target). Upon receiving this callback,
         * you should move the item from the old position (dragged.getAdapterPosition()) to new position (target.getAdapterPosition())
         * in your adapter and also call notifyItemMoved(int, int).
         * 拖动某个item的回调,在return前要更新item位置,调用notifyItemMoveddraggedPositiontargetPosition         * viewHolde:正在拖动item
         * target:要拖到的目标
         * @return true 表示消费事件
         */
        @Override
        public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
            //直接按照文档来操作啊,这文档写得太给力了,简直完美!
            myAdapter.notifyItemMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());
            //注意这里有个坑的,itemView 都移动了,对应的数据也要移动
            Collections.swap(list, viewHolder.getAdapterPosition(), target.getAdapterPosition());
            return true;
        }
        /**
         * 谷歌官方文档说明如下:
         * 这个看了一下主要是做左右拖动的回调
         * When a View is swiped, ItemTouchHelper animates it until it goes out of bounds, then calls onSwiped(ViewHolder, int).
         * At this point, you should update your adapter (e.g. remove the item) and call related Adapter#notify event.
         * @param viewHolder
         * @param direction
         */
        @Override
        public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
            //滑动处理
            list.remove(viewHolder.getAdapterPosition());
            myAdapter.notifyItemRemoved(viewHolder.getAdapterPosition());
        }

        /**
         * 官方文档如下:返回true 当前tiem可以被拖动到目标位置后,直接target上,其他的上面的tiem跟着         * 所以要重写这个方法,不然只是拖动的tiem在动,target tiem不动,静止的
         * Return true if the current ViewHolder can be dropped over the the target ViewHolder.
         * @param recyclerView
         * @param current
         * @param target
         * @return
         */
        @Override
        public boolean canDropOver(RecyclerView recyclerView, RecyclerView.ViewHolder current, RecyclerView.ViewHolder target) {
            return true;
        }

        /**
         * 官方文档说明如下:
         * Returns whether ItemTouchHelper should start a drag and drop operation if an item is long pressed.
         * 是否开启长按 拖动
         * @return
         */
        @Override
        public boolean isLongPressDragEnabled() {
            //return true后,可以实现长按拖动排序和拖动动画了
            return true;
        }
    };

}


ItemTouchHelper的方法讲解都在注释中

adapter很简单item也只是一行text


public class MyAdapter extends RecyclerView.Adapter {

    List list;

    public MyAdapter(List list) {
        this.list = list;
    }

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

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        holder.textView.setText(list.get(position));
    }

    @Override
    public int getItemCount() {
        return list == null ? 0 : list.size();
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {
        TextView textView;

        public MyViewHolder(View itemView) {
            super(itemView);
            textView = itemView.findViewById(R.id.tv_serial_number);
        }
    }
}

你可能感兴趣的:(控件使用)