1. 程式人生 > >Android RecycleView拖拽超過一屏發生閃屏無法拖拽的bug的解決方案

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就解決問題了。

修改過的效果如下: