유누킴

[Kotlin] RecyclerView 롱클릭 드래그로 위치 변경하기 본문

Tech/Android

[Kotlin] RecyclerView 롱클릭 드래그로 위치 변경하기

Yunhoo_kim 2019. 1. 10. 11:10
728x90

 RecyclerView 롱클릭 드래그로 위치 변경하기


안드로이드 RecyclerView는 View를 재활용하는 ListView이다.

이번 포스팅에서는 RecyclerView에서 드래그로 아이템들의 순서를 바꾸는 방법에 대하여 설명하겠습니다.


1. RecyclerView Adapter 생성

어댑터를 생성하고 해당 어댑터에서 item swap 하는 swapItems 메소드를 추가한다.

fun swapItems(fromPosition: Int, toPosition: Int) {
        if (fromPosition < toPosition) {
            for (i in fromPosition until toPosition) {
                imageList[i + 1] = imageList[i]
                imageList[i] = imageList[i + 1]
            }
        } else {
            for (i in fromPosition..toPosition + 1) {
                imageList[i - 1] = imageList[i]
                imageList[i] = imageList[i + 1]
            }
        }

        notifyItemMoved(fromPosition, toPosition)
    }

swapItems 메소드에서는 서로 swap되는 포지션을 인자로 받는다.

만약 움직이는 포지션(fromPosition)이 가야하는 포지션(toPosition)보다 큰 경우(뒤에 있음) 하나씩 뒤로 밀고

움직이는 포지션이 가야하는 포지션보다 작은 경우 하나씩 앞으로 당긴 뒤 위치가 움직였다는 notifyItemMove를 호출한다.


이렇게 되면 fromPosition과 toPosition 사이에 있는 item들의 위치도 한번에 수정 가능하다.


2. ItemTouchHelper.SimpleCallback을 구현한 새로운 콜백을 생성한다.

class DragManageAdapter(adapter: ImageDragListAdapter, context: Context, dragDirs: Int, swipeDirs: Int) : ItemTouchHelper.SimpleCallback(dragDirs, swipeDirs)
{
    val dragAdapter = adapter

    override fun onMove(recyclerView: RecyclerView?, source: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean
    {
        dragAdapter.swapItems(source.adapterPosition, target.adapterPosition)
        return true
    }

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

    override fun getSwipeDirs(recyclerView: RecyclerView?, viewHolder: RecyclerView.ViewHolder?): Int {
        return 0
    }
}

ItemTouchHelpe.SimpleCallback을 구현한 DragManageAdapter를 생성하고

onMove, onSwiped, getSwipeDirs를 오버라이딩 한다.

onMove에서는 recyclerView와 source, target을 인자로 넘겨 받아서 이전에 구현한 adapter에 swipeItems 메소드를 호출한다.

getSwipeDirs는 스와이프 터치 이벤트를 받는다. 이때 0을 return 해주게되면 드래그만 가능하고 swipe는 disable 할 수 있다. ** swipe까지 지원하려면 해당 코드를 삭제해야함


3. RecyclerView에 적용하기

binding.imageDrag.apply {
            val manager = GridLayoutManager(this@ThisActivity, 3)
            val callback = DragManageAdapter(viewModel.imageListAdapter, this@ThisActivity,
                ItemTouchHelper.UP.or(ItemTouchHelper.DOWN).or(ItemTouchHelper.LEFT).or(ItemTouchHelper.RIGHT), -1)
            val helper = ItemTouchHelper(callback)
            layoutManager = manager
            helper.attachToRecyclerView(this)
        }

layoutManager는 GridLayoutManager를 사용했고(다른 LayoutManager도 사용가능함),

앞에서 생성한 DragManageAdapter를 recyclerview adapter, context, drag에 사용할 touch event 종류(UP, DOWN, LEFT, RIGHT)를 인자로 넘겨 생성한다.

itemTouchHelper에 callback을 등록하고 recyclerView에 붙여주면 드래그로 위치 변경 가능한 RecyclerView가 완성된다.



이 포스팅은 공부하고 작업한 내용을 기억하고 기록하기위해 작성했습니다.

포스팅 내용중 잘못된 지식이 있을 경우 댓글로 남겨주시면 적극 반영하겠습니다.

읽어 주셔서 감사합니다 :)