Android -- 實現RecyclerView可拖拽Item


1,今天和大家一起實現RecyclerView可拖拽Item,主要是使用RecyclerView結合ItemTouchHelper來實現的,來看一下效果

 

2,看一下怎么實現的呢,很簡單,只需要給recyclerView添加一個ItemTouchHelper對象就行

mItemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() );
mItemTouchHelper.attachToRecyclerView(mRecyclerView);

 構造方法中需要一個CallBack對象,適用於拖拽或者剔除時的回調方法,所以我們主要是要重寫CallBack中的相應方法,處理響應的邏輯

   首先來自定義一個CallBack類,繼承與ItemTouchHepler.Callback()對象

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

            @Override
            public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
              
              
            }

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

            }

  首先說一下getMovementFlags(),這個方法是設置是否滑動時間,以及拖拽的方向,所以在這里需要判斷一下是列表布局還是網格布局,如果是列表布局的話則拖拽方向為DOWN和UP,如果是網格布局的話則是DOWN和UP和LEFT和RIGHT,對應這個方法的代碼如下:

@Override
            public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
                if (recyclerView.getLayoutManager() instanceof GridLayoutManager) {
                    final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN |
                            ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
                    final int swipeFlags = 0;
                    return makeMovementFlags(dragFlags, swipeFlags);
                } else {
                    final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
                    final int swipeFlags = 0;
                    return makeMovementFlags(dragFlags, swipeFlags);
                }
            }

  而onMove()方法則是我們在拖動的時候不斷回調的方法,在這里我們需要將正在拖拽的item和集合的item進行交換元素,然后在通知適配器更新數據,也很簡單,代碼如下:

            @Override
            public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
                //得到當拖拽的viewHolder的Position
                int fromPosition = viewHolder.getAdapterPosition();
                //拿到當前拖拽到的item的viewHolder
                int toPosition = target.getAdapterPosition();
                if (fromPosition < toPosition) {
                    for (int i = fromPosition; i < toPosition; i++) {
                        Collections.swap(datas, i, i + 1);
                    }
                } else {
                    for (int i = fromPosition; i > toPosition; i--) {
                        Collections.swap(datas, i, i - 1);
                    }
                }
                myAdapter.notifyItemMoved(fromPosition, toPosition);
                return true;
            }

  onSwiped()是替換后調用的方法,可以不用管。然后我們希望在拖拽的時候將被拖拽的Item高亮,這樣用戶體驗要好很多,所以我們要重寫CallBack對象中的onSelectedChanged()和clearView()方法,在選中的時候設置高亮背景色,在完成的時候移除高亮背景色,代碼如下:

            /**
             * 長按選中Item的時候開始調用
             *
             * @param viewHolder
             * @param actionState
             */
            @Override
            public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
                if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
                    viewHolder.itemView.setBackgroundColor(Color.LTGRAY);
                }
                super.onSelectedChanged(viewHolder, actionState);
            }

            /**
             * 手指松開的時候還原
             * @param recyclerView
             * @param viewHolder
             */
            @Override
            public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
                super.clearView(recyclerView, viewHolder);
                viewHolder.itemView.setBackgroundColor(0);
            }

  這樣就實現了我們的基本要求,但是實際功能中有可能存在,排頭前兩個的不需改變它的順序,即有些item允許拖拽,有些則不允許,所以我們需要重寫isLongPressDragEnabled()設置不允許長按拖拽

             /**
             * 重寫拖拽不可用
             * @return
             */
            @Override
            public boolean isLongPressDragEnabled() {
                return false;
            }

  然后在重寫RecycleView的長按監聽(這個要自己寫個接口去實現),在返回的長按方法中判斷是否為不可拖拽的item,若不是,則調用ItemTouchHelper的startDrag()方法,邏輯出入如下:

           @Override
            public void onItemLongClick(RecyclerView.ViewHolder vh) {
                //判斷被拖拽的是否是前兩個,如果不是則執行拖拽
                if (vh.getLayoutPosition() != 0 && vh.getLayoutPosition() != 1) {
                    mItemTouchHelper.startDrag(vh);

                }
            }

  為了功耗的用戶體驗 我們可以在長按的時候添加震動,添加權限

<uses-permission android:name="android.permission.VIBRATE" />

  調用方法:

 //獲取系統震動服務
 Vibrator vib = (Vibrator) getSystemService(Service.VIBRATOR_SERVICE);
//震動70毫秒
 vib.vibrate(70);

  這樣功能就差不多實現了,這是GitHub下載鏈接  See You Next Time !


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM