본문 바로가기
Android/View

[Android] 리싸이클러뷰(RecyclerView) (2) - Multiple View Type

by 태크민 2024. 10. 24.

 

이전 포스팅에서 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 -> {}
    }

 

 

RecyclerView 메서드 호출 순서

  • getItemCount 함수를 이용하여 Item   갯수가 몇개 인지 판단하고, getItemViewType  불리면서, 현재 뷰의 Position 해당하는 ViewType 판단한다.
  • 이후 onCreateViewHolder에서, ViewType  해당하는 ViewHolder 생성한다.
  • onBindViewHolder 에서는 onCreateViewHolder 에서 생성된 ViewHolder  가져와서 현재 포지션에 맞는 데이터를 뷰홀더안에 뷰들에게 바인딩해준다.
  • 맨처음에는 getItemCount 불리고,   getItemViewType, onCreateViewHolder, onBindViewHolder  연속적으로 호출된다.
  • 어느 시점부터 재사용될 때는 onCreateViewHolder는 불리지 않고, onBindViewHolder만 불린다.

 


참고자료

https://velog.io/@hyeryeong/Android-RecyclerView1-%EC%97%AC%EB%9F%AC-view-%EC%A0%81%EC%9A%A9

 

[Android] RecyclerView(2) - 여러 view 적용

이전 포스팅에서 RecyclerView와 기본 사용법에 대해서 알아보았습니다.onCreateViewHolder의 파라미터를 살펴보면 viewType이 있는 것을 알 수 있습니다. 이러한 viewType은 무엇이고 왜 사용하게 되는 걸까

velog.io

https://lktprogrammer.tistory.com/190

 

[Android] 안드로이드 - RecyclerView의 ViewType 구분하기

RecyclerView는 Adapter가 관리하는 Data Set의 특정 데이터 항목에 대하여 미리 정의된 View를 통해 스크롤이 있는 List 형식으로 표현할 수 있습니다. 이번 포스팅에서는 한 개의 RecyclerView에서 여러 Type

lktprogrammer.tistory.com