RecyclerView를 구현할 때 아이템 클릭 이벤트를 사용하기 위해 Adapter 안에 인터페이스를 선언하고 인터페이스를 상속 받아 함수를 구현하여 사용했었다.
매번 이런식으로 인터페이스를 구현하여 사용하다보니 번거롭기도 하고 코드가 지저분해지는 것 같은 느낌이 들었는데, 이 부분을 람다로 표현하니 코드가 훨씬 간결해지고 보기 편해진 것 같다 ! 😆
class SearchListAdapter() : ListAdapter<SearchModel, SearchListAdapter.ViewHolder>(SearchDiffUtil) {
// 아이템 클릭을 위한 인터페이스 선언
interface ItemClick {
fun onClick(searchModel: SearchModel)
}
var itemClick: ItemClick? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding =
ImageListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding, itemClickListener)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = getItem(position)
holder.bind(item)
}
class ViewHolder(
private val binding: ImageListItemBinding,
private val itemClickListener: ((SearchModel) -> Unit)?
) :
RecyclerView.ViewHolder(binding.root) {
fun bind(item: SearchModel) = with(binding) {
ivImage.setOnClickListener {
itemClick?.onClick(item)
}
}
}
}
// Fragment
private val searchListAdapter by lazy {
SearchListAdapter()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initView()
}
fun initView() {
/*
* Adapter에 아이템 클릭 리스너를 연결한다.
* SearchListAdapter.ItemClick의 인터페이스를 상속받아 함수를 구현한다.
*/
searchListAdapter.itemClick = object : SearchListAdapter.ItemClick {
override fun onClick(searchModel: SearchModel) {
// TODO 버튼 클릭 이벤트
}
}
}
/*
* (SearchModel) -> Unit : parameter 1개를 가진 함수
* Unit : 반환 유형을 지정하지 않는 경우 기본적으로 Unit이 되며, 코틀린에서 값을 반환하지 않음을 의미한다.
*/
class SearchListAdapter(
private val itemClickListener: (SearchModel) -> Unit // 리스트의 아이템에 대한 클릭 리스너
) : ListAdapter<SearchModel, SearchListAdapter.ViewHolder>(SearchDiffUtil) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding =
ImageListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding, itemClickListener) // 바인딩과 리스너를 사용하여 새로운 인스턴스 생성
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = getItem(position)
holder.bind(item)
}
class ViewHolder(
private val binding: ImageListItemBinding,
private val itemClickListener: ((SearchModel) -> Unit)?
) :
RecyclerView.ViewHolder(binding.root) {
fun bind(item: SearchModel) = with(binding) {
ivImage.setOnClickListener {
/*
* invoke는 마치 함수인 것처럼 호출할 수 있도록 하는 규칙이다.
* (SearchModel) -> Unit를 호출하는 데 사용된다.
*/
itemClickListener?.invoke(item)
}
}
}
}
// Fragment
private val searchListAdapter by lazy {
SearchListAdapter(
// 람다식을 사용하면 함수를 선언할 필요가 없고, 코드 블럭을 직접 함수의 인자로 전달 할 수 있다.
itemClickListener = { item ->
// TODO 버튼 클릭 이벤트
}
)
}
invoke
라는 함수, 정확히는 연산자가 존재한다. invoke
연산자는 이름 없이 호출 될 수있다. class MyFunction {
operator fun invoke(str: String): String {
return str.uppercase()
}
}
fun main() {
val myfunction = MyFunction()
println(myfunction.invoke("hello")) // hello
println(myfunction("hello")) // hello
}