RecyclerView的item拖動排序效果以及側滑刪除實現和它的ItemTouchHelper詳解

說明: 
1.實現這個效果的核心類是:ItemTouchHelper和ItemTouchHelper.Callbck. 
2.mainActivity的佈局就是一個recyclerview,item的佈局cardview套着三個控件。

 首先看MAinActivity的代碼吧

public class MainActivity extends AppCompatActivity {

    List<String> 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<MyAdapter.MyViewHolder> {

    List<String> list;

    public MyAdapter(List<String> 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);
        }
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章