[Android] ItemTouchHelper란
ItemTouchHelper란🤷🏻♂️
ItemTouchHelper는 RecyclerView에 삭제를 위한 스와이프 및 드래그 앤 드롭을 지원하는 유틸리티 클래스입니다.
ItemTouchHelper는 사용자가 액션을 수행할 때 이벤트를 수신하는 RecyclerView 및 이벤트에 반응하는 콜백 메서드가 선언되어있는 Callback 클래스와 함께 사용합니다.
즉, 구조적으로 RecyclerView와 ItemTouchHelper.Callback을 ItemTouchHelper가 연결시켜주는 것입니다.
주요 메소드
- attachToRecyclerView(RecyclerView) : ItemTouchHelper를 제공된 RecyclerView에 붙입니다.
ItemTouchHelper.Callback
이 클래스는 앱과 ItemTouchHelper 사이의 계약에 해당하는 클래스입니다. ItemCallback클래스는 각 ViewHolder에 대해 어떠한 터치 행동이 가능한지 제어하고, 사용자가 정의한 액션을 수행할 때 콜백을 받습니다.
주요 메서드
- getMovementFlags(RecyclerView, ViewHolder) : 각각의 뷰에 수행할 수 있는 작업을 컨트롤하기 위해서는, getMovementFlags(RecyclerView, ViewHolder) 메서드를 오버라이드하고 적절한 방향을 반환해야 합니다. makeMovementFlags(Int,Int)를 사용하여 쉽게 구성할 수도 있습니다. 또는 SimpleCallback을 사용할 수 있습니다.
- onMove(RecyclerView, dragged, target) : 만약 사용자가 Item을 Drag한다면, ItemTouchHelper는 onMove를 호출합니다. 이 콜백 메소드를 받으면 Adapter에서 Item을 이전 위치(dragged.getAdapterPosition())에서 새로운 위치(target.getAdapterPosition())로 이동해야 하고, RecyclerView의 Adapter에서 notifyItemMoved(Int, Int)를 호출해야 합니다.
- onSwiped(ViewHolder, Int) : View가 Swipe 되면 ItemTouchHelper는 범위를 벗어날 때까지 View를 애니메이션화한 다음 이 메서드를 호출합니다. 여기서 어댑터를 업데이트해야 하고 관련된 Adapter의 notify이벤트를 호출해야 합니다.
예제🔥
ItemTouchHelperListener
RecyclerViewAdapter와 ItemTouchHelper.Callback을 연결시켜주는 리스너입니다.
interface ItemTouchHelperListener {
fun onItemMove(from : Int,to:Int) : Boolean
fun onItemSwipe(position:Int)
}
RecyclerView의 Item이 Drag 되거나 Swipe 될 때 호출되는 메서드를 가진 인터페이스입니다.
ItemTouchHelperCallback
class ItemTouchHelperCallback(private val listener:ItemTouchHelperListener) : ItemTouchHelper.Callback() {
//활성화된 이동 방향을 정의하는 플래그를 반환하는 메소드
override fun getMovementFlags(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder
): Int {
val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
val swipeFlgs = ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
return makeMovementFlags(dragFlags,swipeFlgs)
}
//드래그된 Item을 새로운 위치로 옮길때 호출
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
return listener.onItemMove(viewHolder.adapterPosition,target.adapterPosition)
}
//사용자에 의해 swipe될 때 호출
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
listener.onItemSwipe(viewHolder.adapterPosition)
}
}
RecyclerViewAdapter
//RecyclerView에 뿌려줄 data리스트를 RecyclerView에 바인딩 시켜주기 위한 사전 작업이 이루어지는 객체
class RecyclerViewAdapter(private val dataList:MutableList<String>) : RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>(),ItemTouchHelperListener{
//뷰 객체를 기억하고 있을 홀딩 객체
class ViewHolder(view : View): RecyclerView.ViewHolder(view){
val textview = view.findViewById<TextView>(R.id.data_text)
}
//ViewHolder 객체가 생성되는 함수
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): ViewHolder {
return ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_layout,parent,false))
}
//생성된 ViewHolder에 데이터를 바인딩해주는 함수
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.textview.text = dataList[position]
}
//RecyclerView의 뿌려줄 아이템 개수
override fun getItemCount(): Int = dataList.size
override fun onItemMove(from: Int, to: Int) : Boolean {
val data = dataList[from]
//리스트 갱신
dataList.removeAt(from)
dataList.add(to,data)
// from에서 to 위치로 아이템 위치 변경
notifyItemMoved(from,to)
return true
}
// 아이템 스와이프되면 호출되는 메소드
override fun onItemSwipe(position: Int) {
// 리스트 아이템 삭제
dataList.removeAt(position)
notifyItemRemoved(position)
}
}
기존에 RecyclerView.Adapter에 ItemTouchHelperListener 리스너를 상속받아 onItemMove 메서드와 onItemSwipe 메서드를 오버라이드 해서 구현했습니다.
onItemMove 메서드는 Item이 Drag될 때 사용되는 메소드입니다. 코드는 Item 리스트에서 Drag 되는 아이템을 갱신하고 notifyItemMoved를 호출하여 Item이 새로운 위치로 변경됐음을 알립니다.
onItemSwipe 메소드는 항목이 Swipe 될 때 사용되는 메서드입니다. 코드는 Item이 Swipe 되면 그 Item을 삭제하기 위해 Item 리스트에서 해당 위치의 Item을 삭제하고 notifyItemRemoved를 호출하여 해당 위치의 Item이 삭제되었다는 것을 알립니다.
MainActivity
//데이터
val data = MutableList(100){
"Item $it"
}
recyclerView.layoutManager = LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false)
//Adapter
val adapter = RecyclerViewAdapter(data)
recyclerView.adapter = adapter
//리스너를 구현한 Adapter 클래스를 Callback 클래스의 생성자로 지정
val itemTouchHelperCallback = ItemTouchHelperCallback(adapter)
//ItemTouchHelper의 생성자로 ItemTouchHelper.Callback 객체 설정
val helper = ItemTouchHelper(itemTouchHelperCallback)
//RecyclerView에 ItemTouchHelper 연결
helper.attachToRecyclerView(recyclerView)
ItemTouchHelper.Callback 객체를 ItemTouchHelper 클래스의 생성자로 넣어서 주어진 콜백 클래스로 동작하는 ItemTouchHelper 객체를 생성합니다. ItemTouchHelper.attachToRecyclerView(Recyclerview) 메서드로 RecyclerView와 연결해주시면 됩니다.
동작 화면🔍
출처👍🏻
https://velog.io/@changhee09/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-ItemTouchHelper