이전 포스팅에서 RecyclerView와 기본 사용법에 대해서 알아보았습니다.
onCreateViewHolder의 파라미터를 살펴보면 viewType이 있는 것을 알 수 있습니다.
이러한 viewType은 무엇이고 왜 사용하게 되는 걸까요?
viewType이란?
viewType은 변수명 그대로 viewType에 의해 구분되어 들어오는 값을 말합니다.
RecyclerView 안의 개별 View가 모두 같은 타입인 경우만 있지는 않습니다. 예를 들어, 채팅 UI를 가지는 경우를 보면 View들이 서로 다른 Layout을 가져야 합니다. 또는, RecyclerView에 header나 footer를 추가하고 싶을 때에도 View를 다르게 구성해야 합니다.
이런 경우에 유용하게 되는 것이 바로 viewType입니다.
viewType을 이용하고 싶다면 우선적으로 오바라이드할 함수가 있습니다.
✏️ getItemViewType
파라미터로 position을 전달받게 되면 리스트에서 해당 position의 데이터를 확인해서 원하는 viewType을 return하도록 합니다.
override fun getItemViewType(position: Int): Int {
return datas[position].type
}
type에 따른 ViewHolder를 지정하기 위해서 우선적으로 필요한 작업이 있습니다.
viewType은 다르게 하고 싶지만, 표시될 데이터들이 같은 type인 경우에는 data class에 type을 추가하면 됩니다.
data class MultiData(
val image : Int,
val name : String,
val age : Int,
val type : Int
)
🔎 data 타입이 다른 경우에는 어떻게 할 수 있을까요?
우선 data들이 모두 한 리스트에 존재해야 하므로 같은 클래스를 상속받고 있거나, 하나의 클래스가 다른 클래스를 상속받고 있게 해줍니다.
interface Item
data class ItemOne(
val title: String
) : Item
data class ItemTwo(
val title: String,
val address: String
) : Item
그러면 getItemViewType이 이렇게 동작하도록 할 수 있습니다.
override fun getItemViewType(position: Int) = when (items[position]) {
is ItemOne -> {
TYPE_ONE
}
is ItemTwo -> {
TYPE_TWO
}
else -> {
throw IllegalStateException("Not Found ViewHolder Type")
}
}
✏️ onCreateViewHolder
onCreateViewHolder은 내부적으로 position에 해당하는 viewType을 파라미터로 받게 됩니다. 이때, 위에서 오버라이드한 getItemViewType함수를 사용합니다.
viewType에 맞는 ViewHolder을 생성하기 위해서는, 다양한 View에 맞는 다양한 ViewHolder를 정의해야 합니다.
class ViewHolderOne(binding:VisitedItemBinding):RecyclerView.ViewHolder(binding.root){
val binding = binding
fun bind(item:ItemOne){
binding.titleView.text = item.title
}
}
class ViewHolderTwo(binding:VisitedNamedItemBinding):RecyclerView.ViewHolder(binding.root){
val binding = binding
fun bind(item:ItemTwo){
binding.titleView.text= item.title
binding.addrView.text = item.address
}
}
그 뒤에 onCreateViewHolder에서 viewType에 맞게 ViewHolder를 생성합니다.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
if(viewType == TYPE_ONE){
val view = OneRowBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolderOne(view)
}
else{
val view = TwoRowBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolderTwo(view)
}
}
✏️ onBindViewHolder
그렇다면 onBindViewHolder에서는 어떻게 적용할 수 있을까요?
onBindViewHolder에서는 데이터를 바인딩하기 전에 holder.itemViewType을 통해서 viewType을 확인한 뒤에 데이터를 바인딩하면 됩니다.
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
...
when (holder.itemViewType) {
TYPE_ONE -> (holder as ViewHolderOne).bind(datas[position] as ItemOne)
TYPE_TWO-> (holder as ViewHolderTwo).bind(datas[position] as ItemTwo)
else -> {}
}
}