본문 바로가기
안드로이드

[android] 리사이클러뷰 아이템을 드래그해서 위치 바꾸기

by 아이디생성자 2022. 11. 9.

기억에서 희미해져가는 드래그 기능을 다시 한번 짜보았다.

십이간지 순서 바꾸기

아주 부드럽게 잘 되는 것 같다.

 

Activity

class DragActivity : AppCompatActivity() {

    private lateinit var binding: ActivityDragBinding

    private var animalDragAdapter: DragAdapter? = null

    private val animalList = arrayListOf(
        "쥐",
        "소",
        "호랑이",
        "토끼",
        "용",
        "뱀",
        "말",
        "양",
        "원숭이",
        "닭",
        "개",
        "돼지"
    )

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityDragBinding.inflate(layoutInflater)
        setContentView(binding.root)

        animalDragAdapter = DragAdapter(animalList, binding.rvAnimal)
    }
}

 

어댑터안에 모두 때려박아서 데이터와 어댑터 연결뿐인 액티비티...

(단순히 본인의 간편한 테스트를 위해 축소 작성된 코드)

 

 

Adapter

class DragAdapter(
    private val items: ArrayList<String>,
    private val dragRecyclerview: RecyclerView
) : RecyclerView.Adapter<DragAdapter.DragViewHolder>(){
    // 리사이클러뷰 터치 헬퍼
    private var itemDragHelper: ItemTouchHelper? = null
    // 드래그 위치 변경 콜백리스너
    private val helperCallback = DragHelperCallback { fromPos, toPos ->
        Collections.swap(items, fromPos, toPos)
        notifyItemMoved(fromPos, toPos)
        Log.d("시작: $fromPos", "변경: $toPos")
        Log.d("items", "$items")
        true
    }

    init {
        dragRecyclerview.adapter = this

        itemDragHelper = ItemTouchHelper(helperCallback).apply {
            attachToRecyclerView(dragRecyclerview)
        }
    }

    @SuppressLint("ClickableViewAccessibility")
    override fun onBindViewHolder(holder: DragViewHolder, position: Int) {
        holder.viewDataBinding.run {
            tvDrag.text = items[position]

            // 드래그 이벤트 시작 (부드러운 사용을 위해 버튼 터치다운시 바로 드래그 시작)
            ibDrag.setOnTouchListener { _, motionEvent ->
                if (motionEvent.action == MotionEvent.ACTION_DOWN) {
                    itemDragHelper?.startDrag(holder)
                }

                return@setOnTouchListener false
            }
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DragViewHolder {
        return DragViewHolder(
            LayoutInflater.from(parent.context).inflate(R.layout.item_drag, parent, false)
        )
    }

    inner class DragViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val viewDataBinding = ItemDragBinding.bind(view)
    }

    override fun getItemCount(): Int = items.size

    inner class DragHelperCallback(
        private val actionDrag: (Int, Int) -> Boolean
    ) : ItemTouchHelper.Callback() {

        override fun getMovementFlags(
            recyclerView: RecyclerView,
            viewHolder: RecyclerView.ViewHolder
        ): Int {
            // 상하 드래그시
            val dragFlag = ItemTouchHelper.UP or ItemTouchHelper.DOWN
            // 좌우 드래그시
//            val dragFlag = ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
            return makeMovementFlags(dragFlag, 0)
        }

        override fun onMove(
            recyclerView: RecyclerView,
            viewHolder: RecyclerView.ViewHolder,
            target: RecyclerView.ViewHolder
        ): Boolean {
            // 시작 위치와 변경되는 위치 전달
            return actionDrag.invoke(viewHolder.adapterPosition, target.adapterPosition)
        }

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

        // 사용x
        override fun isLongPressDragEnabled(): Boolean = false

    }
}

 

개인적으로 isLongPressDragEnabled를 사용하는 것 보다 낫다고 생각된다.

댓글