짜잔!

간단하게 구현한 결과 화면부터 감상하시죠

 

 

 

 

 

 

 

자 오늘은 RecyclerView의 Drag&Drop / Swipe 기능을 알아보겠습니다.

 

RecyclerView에 대한 내용은 아래의 내용을 참고해주세요!

 

[Android] Kotlin RecyclerView 알아보기

이름에서 알 수 있듯이 RecyclerView는 이러한 개별 요소를 재활용합니다. 항목이 스크롤되어 화면에서 벗어나더라도 RecyclerView는 뷰를 제거하지 않습니다. 대신 RecyclerView는 화면에서 스크롤된 새

salmonpack.tistory.com

 

 


우선 위와 같은 기능 구현을 하기 위한 준비 단계를 알아보겠습니다.

 

  • RecyclerView / RecyclerView Adapter 구현
  • ItemTouchHelper Callback 구현
  • RecyclerView Adapter에서 Interface 적용하여 사용

 

RecycleView와 Adapter는 구현되어 있다고 가정하겠습니다.

 

그러면 우선 Class를 하나 구현하여 

ItemTouchHelper Callback의 

  • getMovementFlags()
  • onMove()
  • onSwiped()
  • isLongPressDragEnabled()
  • isItemViewSwipeEnabled()

메서드들을 overried 하여 구현합니다.

 

interface ItemTouchHelperListener {
    fun onItemMove(formPosition: Int, toPosition: Int): Boolean
    fun onItemSwipe(position: Int)
}

 

class ItemTouchHelperCallback(
    val listener: ItemTouchHelperListener
): ItemTouchHelper.Callback() {

    private var itemTouchHelperListener: ItemTouchHelperListener = listener

    override fun isLongPressDragEnabled(): Boolean {
        return true
    }

    override fun isItemViewSwipeEnabled(): Boolean {
        return true
    }

    override fun getMovementFlags(
        recyclerView: RecyclerView,
        viewHolder: RecyclerView.ViewHolder
    ): Int {
        val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
        val swipeFlags = ItemTouchHelper.START or ItemTouchHelper.END
        return makeMovementFlags(dragFlags, swipeFlags)
    }

    override fun onMove(
        recyclerView: RecyclerView,
        viewHolder: RecyclerView.ViewHolder,
        target: RecyclerView.ViewHolder
    ): Boolean {
        itemTouchHelperListener.onItemMove(
            viewHolder.adapterPosition,
            target.adapterPosition
        )
        return true
    }

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

 

getMovementFlags에서 drag의 방향 또는 swipe의 방향에 대한 값을

입력하여 makeMovementFlags에서 Int값으로 변환받습니다.

 

여기서 drag 또는 swipe 중 하나의 기능만 구현한다면

  • Drag - return makeMovementFlags(dragFlags, 0) + onMove()
  • Swipe - return makeMovementFlags(0, swipeFlags) + onSwiped()

이렇게 구현해주시면 될 것 같습니다.

 

 


다음은 RecyclerView Adpater에서 위에서 구현한 ItemTouchHelperListener 인터페이스를 상속받아

onItemMove() , onItemSwipe()를 override 하여 구현합니다.

 

class RecyclerViewAdapter(
    private val list: MutableList<ItemData>
): RecyclerView.Adapter<RecyclerViewAdapter.RecyclerViewHolder>(),
    ItemTouchHelperListener {
    
    ...
    
    override fun onItemMove(formPosition: Int, toPosition: Int): Boolean {
        val formItem: ItemData = itemLists[formPosition]
        val toItem: ItemData = itemLists[toPosition]

        itemLists[formPosition] = toItem
        itemLists[toPosition] = formItem

        notifyItemMoved(formPosition,toPosition);
        return true
    }

    override fun onItemSwipe(position: Int) {
        itemLists.removeAt(position)
        notifyItemRemoved(position)
    }
    
    ...
    
}

 

notifyItemMoved() , notfyItemRemoved() 관련하여

아래 내용을 참조하여 주시고

 

 

[Android] RecyclerView 깜빡이는 현상 해결 (notifyDataSetChanged)

혹시 RecyclerView를 사용하면서 RecyclerView의 데이터 삭제 또는 추가 과정에서 RecyclerView가 깜빡이는 현상 때문에 고생하셨나요?? via GIPHY 위와 같은 현상에 대해서 알아보도록 하겠습니다. [Android] Kot

salmonpack.tistory.com

 

여기서 설명드린 RecyclerView onHasStabled() 메서드와 getItemId()를 구현하면,

위의  ItemToucherHelper의 동작이 정상 작동하지 않는 이슈를 발견했습니다.

 

setHasStableIds(true)

override fun getItemId(position: Int): Long {
    return position.toLong()
}

// 두 가지를 구현했을 경우 ItemTouchHelper 구현이 정상적이지 않음

 

정확한 원인은 모르겠지만...

ItemTouchHelper getMovementFlags 동작 관련하여

내부적으로 item의 위치 이동 또는 삭제 시 

item의 id 값을 이용하여 동작하는데,

setHasStabledIds / getItemId 값을 이용하여

item 값의 id를 기존과 다르게 사용하여 생기는 문제가 아닌가...

 

(혹시나 정확한 이유를 아신다면 댓글로 저의 부족한 지식을 채워 주세요...)

 

 

 


마지막입니다.

ItemToucheHelper에 구현한 Adapter와 RecyclerView를 연결시켜주면 됩니다.

 

rvAdapter = RecyclerViewAdapter(list)
binding.rvEx.adapter = rvAdapter

ItemTouchHelper(ItemTouchHelperCallback(rvAdapter)).apply {
     attachToRecyclerView(binding.rvEx)
}

 

 

 


여기까지 저의 긴 글을 읽어주셔서 감사합니다.

제가 습관적으로 코딩을 하는 그날까지 습관적으로 코딩을 하기 위해 글 작성을 꾸준하게 해보겠습니다.

 

 

 

 

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기