RecyclerView Item 드래그 앤 드랍(Drag and Drop) 순서 변경

2021. 6. 9. 16:17모바일/Android_Kotlin

RecyclerView Item 드래그 앤 드랍(Drag and Drop) 순서 변경

예전 listview를 사용했을때.. itemTouchHelper가 없을 시절에는 커스텀 리스트뷰를 만들어 일일히 구현을 했었다

onInterceptTouchEvent, onTouchEvent 에 터치 이벤트를 가로채고.. 터치된 이벤트에 y 좌표를 계산하고

ACTION_DOWN에서 놓은 좌표의 y값을 계산해서 아이템의 순서를 리턴했었다

하지만 이 복잡한 과정들을 RecyclerView 와 ItemTouchHelper가 매우 쉽게 만들어 주었는데 코드를 하나하나 짚어보면서 확인해보자

ItemTouchHelper.CallBack()

먼저 ItemTouchHelper의 콜백 함수를 Implement 하여 움직임이 있을때, 어떤 방향으로 움직였을때 RecyclerView Item들의 순서를 변경시킬지

구현하도록 한다.

val mItemTouchCallback = object : ItemTouchHelper.Callback() {
  override fun getMovementFlags(
    recyclerView: RecyclerView,
    viewHolder: RecyclerView.ViewHolder
  ): Int {
    //어떤 방향으로 드래그, 스와이프 되었는지 알기 위해서 반드시 구현해야한다.
    return makeFlag(
      ItemTouchHelper.ACTION_STATE_DRAG,
      ItemTouchHelper.DOWN or ItemTouchHelper.UP or ItemTouchHelper.START or ItemTouchHelper.END
    )
  }
  override fun onMove(
    recyclerView: RecyclerView,
    viewHolder: RecyclerView.ViewHolder,
    target: RecyclerView.ViewHolder
  ): Boolean {
    //데이터를 드래그하여 안드로이드 플랫폼에서 드래그한 데이터가 기존 데이터의 위치를 밀어내면 호출된다.
    mViewModel.currentIndexList.value?.run { (this:List<IndexData>)
      if (!get(viewHolder.absoluteAdapterPosition).isEditable || !get(target.absoluteAdapterPosition).isEditable) {
        return false
      }
            //움직임 이전 위치와 움직일곳의 위치를 반환한다
      val fromPosition = viewHolder.absoluteAdapterPosition
      val toPosition = target.absoluteAdapterPosition

      //뷰모델에 변경된 인덱스를 셋팅한다
      if (fromPosition < toPosition) {
        for (i in fromPosition until toPosition) {
          Collections.swap(this, i, i + 1)
          mViewModel.swapOrderNumberPosition(get(i), get(i + 1))
        }
      } else {
        for (i in fromPosition downTo toPosition + 1) {
          Collections.swap(this, i, i - 1)
          mViewModel.swapOrderNumberPosition(get(i), get(i - 1))
        }
      }
    }

    mCurrentIndexAdapter.notifyItemMoved(
      viewHolder.absoluteAdapterPosition,
      target.absoluteAdapterPosition
    )
    return true
  }

  override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
  }
}

//ItemTouchHelper클래스에 콜백 함수를 등록한다
val itemTouchHelper = ItemTouchHelper(mItemTouchCallback)
//itemtouchHelper에 Recyclerver를 attach한다.
itemTouchHelper.attachToRecyclerView(mBinding.currentIndexList)

참..쉽죠?

개발하기가 정말 편해진것 같습니다!