Android RecycleView拖拽超過一屏發生閃屏無法拖拽的bug的解決方案
公司新的需求中需要使用拖拽排序的功能,使用RecycleView加上ItemTouchHelper來實現。實現比較簡單,但是出現了拖拽超過一屏發生閃動,並自動結束了自動排序的問題,以下是功能實現,解決方案在文章最後加粗顯示。
1.初始化RecyclerView,併為RecyclerView新增LinearLayoutManager,並setOrientation為VERTICAL
2.編寫相關的Adapter,在Adapter中設定長按回調,並設定到RecyclerView中
3.初始化ItemTouchHelper,
(1)重寫getMovementFlags設定是否支援上下左右拖拽,當前功能使用LinearLayoutManager需要支援上下拖拽
@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); } }
當為 GridLayoutManager時,可支援上下左右拖拽,當為其他時支援上下拖拽。
(2)重寫onMove方法,資料交換的邏輯就在這個方法中實現。
(3)重寫isLongPressDragEnabled方法,我這裡設定為return false,表示長按整個item不能拖拽,在Adapter的長按回調中呼叫 itemTouchHelper.startDrag(viewHolder); 方法,開始拖拽。
(4)重寫onSelectedChanged方法,實現當拖拽的item選中時的一些邏輯,我這裡當item被選中時,將整個item設定為半透明。
@Override public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { if(!(viewHolder instanceof TTripDayEditDragAdapter.MoveItemViewHolder)) { return; } if (viewHolder != null) { int position = viewHolder.getAdapterPosition(); moveStartPosition = position; } if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) { viewHolder.itemView.setAlpha(0.5f); ((TTripDayEditDragAdapter.MoveItemViewHolder) viewHolder).rl_distance_plan.setVisibility( View.GONE); } super.onSelectedChanged(viewHolder, actionState); }
(5)重寫clearView方法,實現當拖拽完成時需要的邏輯,我這裡將item設定為不透明
@Override public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { super.clearView(recyclerView, viewHolder); if(!(viewHolder instanceof TTripDayEditDragAdapter.MoveItemViewHolder)) { return; } moveEndPosition = viewHolder.getAdapterPosition(); viewHolder.itemView.setAlpha(1f); ((TTripDayEditDragAdapter.MoveItemViewHolder) viewHolder).rl_distance_plan.setVisibility( View.VISIBLE); handleMapData(); refreshPoiDistance(); }
實現完成,新增資料進行測試的時候出現了一個問題,就是當拖拽超過一屏時,RecyclerView會有閃爍,並且自動結束了拖拽,如下圖
可以看到,我的手指並沒有離開螢幕,但是超過一屏之後RecyclerView自動結束了拖動排序。
經過長時間的排查,其實原因很簡單,解決方案如下:
因為我把RecyclerView的layout_height寫成了wrap_content,導致超過一屏之後,RecyclerView重新計算高度,所以就取消了拖拽的功能,將wrap_content改為match_parent就解決問題了。
修改過的效果如下: