리사이클러뷰 아이템들을 클릭이벤트 설정과 생성, 수정, 삭제하는 방법에 대해 설명하고자 한다.
보통 당근마켓의 판매글과 같이 사용자가 무언가를 올리고 이를 관리할 때 많이 사용한다.
리사이클러뷰 아이템 클릭 이벤트
클릭 이벤트를 구현하기 위한 방법은 holder.itemView.setOnclickListener{} 형식으로 onBindViewHolder 메소드 내에서 지정하는 방법 또는 itemView.setOnclickListener{} 형식으로 뷰홀더 내에서 클릭이벤트를 지정하는 방법이있다.
그러나 액티비티나 프래그먼트에서 사용하고자 한다면 리사이클러뷰는 따로 클릭 이벤트를 지정해 주는 함수가 없기 때문에 아이템 클릭 이벤트를 따로 지정해 주어야 한다.
이를 커스텀 리스너라고도 한다. interface로 클래스를 구현하여 이를 액티비티나 프레그먼트 내에서 해당 객체를 전달하여 사용 가능하다.
리사이클러뷰 커스텀 클릭 리스너
1. 커스텀 리스너 인터페이스 정의
RecyclerViewAdapter.kt
// 아이템 클릭시 interface로 클래스 선언
interface CustomItemClickListener{
fun onItemClick()
}
2. 리스너 객체를 전달하는 메서드와 전달된 객체를 저장할 변수 추가
RecyclerViewAdapter.kt
// 전달된 객체를 저장할 변수 추가
private lateinit var cItemClickListener: CustomItemClickListener
// 리스너 객체를 전달하는 메서드
fun setCustomItemClickListener(itemClickListener: CustomItemClickListener){
cItemClickListener = itemClickListener
}
3. 액티비티 내에서 구현한함수 사용
MainActivity.kt
recyclerViewAdapter.setCustomItemClickListener(object: RecyclerViewAdapter.CustomItemClickListener{
override fun onItemClick() {
// 원하는 아이템 클릭시 이벤트 구현
TODO("Not yet implemented")
}
})
4. 이후 어댑터에 클릭리스너 함수에 앞서 구현한 함수 호출
MainActivity.kt
override fun onBindViewHolder(holder: RecyclerViewAdapter.ViewHolder, position: Int) {
holder.bind(itemsData[position])
// 리사이클러뷰 클릭 이벤트 안에 앞서 구현한 클릭 함수를 호출한다.
holder.itemView.setOnClickListener{cItemClickListener.onItemClick()}
}
5. 원하는 클릭 이벤트를 액티비티나 프래그먼트에서 구현 여기에 나의 경우 해당 아이템뷰 클릭시 다이얼로그를 띄우고 해당 아이템 뷰의 포지션 값을 받아와 이를 띄우고자 한다.
dialog_edit.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<EditText
android:id="@+id/et_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginTop="16dp"
android:layout_marginRight="4dp"
android:layout_marginBottom="4dp"
android:hint="title"
android:inputType="text" />
<EditText
android:id="@+id/et_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginTop="4dp"
android:layout_marginRight="4dp"
android:layout_marginBottom="16dp"
android:hint="contents"
android:inputType="text" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.button.MaterialButton
android:id="@+id/bt_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:text="수정" />
<com.google.android.material.button.MaterialButton
android:id="@+id/bt_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/bt_edit"
android:text="삭제" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
MainActivity.kt
fun editDialog(title: String, content: String){
AlertDialog.Builder(this)
.setView(R.layout.dialog_edit)
.show()
.also { alertDialog ->
if(alertDialog == null) {
return@also
}
alertDialog.findViewById<EditText>(R.id.et_title)?.setText("$title")
alertDialog.findViewById<EditText>(R.id.et_content)?.setText("$content")
}
간단하게 메인액티비티에 아이템 데이터 값을 받아 커스텀 다이얼로그를 띄우는 함수를 만들어 보았다.
6. 이후 인터페이스 메소드에 데이터를 매개 변수로 추가하고 해당 포지션에 해당하는 값을 onBindView 함수에서 전달한 뒤 메인 액티비티에서 이를 전달한다.
RecyclerViewAdapter.kt
interface CustomItemClickListener{
// 아이템 데이터를 받는 매개 변수 추가
fun onItemClick(itemsData: ItemsData)
}
// 바인딩한 데이터를 홀더에 넣어준다.
override fun onBindViewHolder(holder: RecyclerViewAdapter.ViewHolder, position: Int) {
holder.bind(itemsData[position])
// 리사이클러뷰 클릭 이벤트 안에 앞서 구현한 클릭 함수를 호출한다.
holder.itemView.setOnClickListener { cItemClickListener.onItemClick(itemsData[position]) } // 해당 포지션에 해당하는 데이터 전달
}
7. 아이템 클릭 리스너에 아이템 데이터를 받는 매개변수를 추가한뒤 데이터를 다이얼로그 함수에 전달한다.
MainActivity.kt
recyclerViewAdapter.setCustomItemClickListener(object: RecyclerViewAdapter.CustomItemClickListener{
// 아이템 데이터 전달
override fun onItemClick(itemsData: ItemsData) {
editDialog(itemsData.title, itemsData.number)
}
})
구현 영상
정상적으로 아이템 데이터를 받아와 다이얼로그에 띄우는 것을 확인 할 수 있다.
리사이클러뷰 아이템 CRUD
리사이클러뷰 추가
추가하는 법은 간단하다. ArrayList에 데이터를 추가한뒤 갱신처리를 하면 된다.
먼저 레이아웃에 플러팅액션버튼을 하나 추가 하였다.
activity_main.xml
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_baseline_add_24"
android:layout_margin="40dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
이후 어댑터 클래스에서 데이터를 추가하는 함수를 만들고 갱신처리를 한뒤 플러팅액션버튼을 클릭시 마다 아이템이 생성 되겠끔 하였다.
RecyclerViewAdapter.kt
fun addItem(){
// 데이터 추가
itemsData.add(ItemsData(R.drawable.ic_launcher_foreground, "리사이클러뷰${itemsData.size+1}", "${itemsData.size+1} 번입니다."))
// 데이터 추가 갱신 함수
notifyItemInserted(itemsData.size)
}
MainActivity.kt
binding.fbtAddItem.setOnClickListener{
recyclerViewAdapter.addItem()
}
리사이클러뷰 수정, 삭제
원하는 아이템을 수정, 삭제하려면 해당하는 아이템의 포지션값을 알아야한다.
아이템 클릭시 다이얼로그 창에서 수정, 삭제를 구현 할 것이기 때문에 포지션값을 다이얼로그를 생성하는 함수에 전달하여야 한다.
1. 기존의 어댑터 클래스의 CustomClickListener에 포지션을 받는 매개 변수를 추가한뒤, 이를 onBindView 함수에서 해당 포지션값을 전달한다.
RecyclerViewAdapter.kt
// 아이템 클릭시 interface로 클래스 선언
interface CustomItemClickListener{
// 아이템 데이터를 받는 매개 변수 추가, 포지션 값 추가
fun onItemClick(itemsData: ItemsData, position: Int)
}
override fun onBindViewHolder(holder: RecyclerViewAdapter.ViewHolder, position: Int) {
holder.bind(itemsData[position])
// 아이템 데이터 및 포지션값 추가
holder.itemView.setOnClickListener{cItemClickListener.onItemClick(itemsData[position], position)}// 해당 포지션에 해당하는 데이터 전달
}
2. 아이템을 수정하는 함수와 삭제하는 함수를 만들어준다. 각각 데이터를 저장하고 삭제하는 기능을 넣어 주었다. RecyclerViewAdapter.kt
// 아이템 수정 함수
fun editItem(position: Int, editTitle: String, editContent: String){
// 데이터 변경
itemsData[position] = ItemsData(itemsData[position].Image, editTitle, editContent)
// 해당 아이템만 변경
notifyItemChanged(position)
}
// 아이템 삭제 함수
fun removeItem(position: Int){
itemsData.removeAt(position)
// 전체 아이템 크기 및 아이템 변경
notifyDataSetChanged()
}
이때 notifyItemChanged()와 notifyDataSetChanged()는 리사이클러뷰의 갱신처리를 담당하는 함수이므로 공부가 필요하다.
notify 함수 관련 링크: https://todaycode.tistory.com/55
3. 이후 메인액티비티에 아이템 클릭 리스너에서 position 값을 추가한 뒤 이를 다이얼 로그 함수에도 전달한다.
MainActivity.kt
recyclerViewAdapter.setCustomItemClickListener(object: RecyclerViewAdapter.CustomItemClickListener{
// 아이템 데이터 전달, 포지션 전달
override fun onItemClick(itemsData: ItemsData, position: Int) {
editDialog(itemsData.title, itemsData.number, position)
}
})
fun editDialog(title: String, content: String, position: Int){
AlertDialog.Builder(this)
.setView(R.layout.dialog_edit)
.show().also {...}
}
4. 마지막으로 다이얼로그 함수 안에 수정, 삭제 버튼 클릭시 리사이클러뷰어댑터의 데이터 저장 및 삭제하는 함수를 불러온다.
MainActivity.kt
btEdit?.setOnClickListener{
alertDialog.dismiss()
val editTitle = alertDialog.findViewById<EditText>(R.id.et_title)?.text.toString()
val editContent = alertDialog.findViewById<EditText>(R.id.et_content)?.text.toString()
recyclerViewAdapter.editItem(position, editTitle, editContent)
}
btDelete?.setOnClickListener{
recyclerViewAdapter.removeItem(position)
alertDialog.dismiss()
}
구현영상
전체코드는 해당 링크에 올려두었다.
GitHub - seungjunGong/Test-RecyclerView: 리사이클러뷰 뽀개기
리사이클러뷰 뽀개기. Contribute to seungjunGong/Test-RecyclerView development by creating an account on GitHub.
github.com
오늘은 리사이클러뷰의 클릭 이벤트를 설정하는 법과 리사이클러뷰의 CRUD에 대해서 다루어 보았다.
리사이클러뷰의 CRUD는 서버와 연동하면 사실 데이터를 받아 새로 리사이클러뷰를 그리면 되겠지만
서버와 연동하지 않고 사용하는 경우도 많기 때문에 배워 두는 것이 좋을 것이다.
'android' 카테고리의 다른 글
Android - 리사이클러뷰 뽀개기(1) - 리사이클러뷰 사용법 (0) | 2022.10.24 |
---|---|
Android - Coroutine(코루틴) (0) | 2022.10.15 |
Android Manifest 와 4대 컴포넌트 (0) | 2022.10.02 |
Kotlin 추상화 & 상속 (1) | 2022.09.08 |