IT 프로그래밍-Android

RecyclerView에서 ViewHolder 여러 가지 사용하기

godsangin 2020. 4. 14. 22:45
반응형

RecyclerView를 사용할 때 RecyclerView.Adapter를 사용하게 됩니다. 만약 같은 RecyclerView에서 다른 모양의 view를 보여주기 위해서는 어떻게 해야할까요 ??

예를들어 리스트를 Date별로 정렬하고 일수에 따라 구분선이 필요할 경우가 있죠..!

오늘은 RecyclerView에 서로 다른 View를 정의하는 방법에 대해서 이야기 하도록 하겠습니다.

서로 다른 두 개의 Class가 있다고 가정해 보겠습니다.

첫번째는 Place라는 클래스이고 또 하나는 NamedPlace라는 클래스입니다. 클래스 구조는 NamedPlace가 Place를 상속하고 있습니다.

이와 같은 경우 다음과 같이 두 가지의 View로 나타낼 수 있습니다.

import android.util.Log
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.myhome.realload.databinding.VisitedItemBinding
import com.myhome.realload.databinding.VisitedNamedItemBinding
import com.myhome.realload.db.AppDatabase
import com.myhome.realload.model.NamedPlace
import com.myhome.realload.model.Place

class VisitedRecyclerViewAdapter :RecyclerView.Adapter<RecyclerView.ViewHolder>(){
    var items:ArrayList<Place> = ArrayList()
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        if(viewType == 0){
            val visitedItemBinding = VisitedItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
            val holder = ViewHolder(visitedItemBinding)
            return holder
        }
        else{
            val visitedItemBinding = VisitedNamedItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
            val holder = NamedViewHolder(visitedItemBinding)
            return holder
        }

    }

    override fun getItemCount(): Int {
        return items.size
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        if(holder.itemViewType == 0){
            (holder as ViewHolder).bind(items[position])
        }
        else{
            (holder as NamedViewHolder).bind(items[position] as NamedPlace)
        }
    }
    override fun getItemViewType(position: Int): Int {
        if(items[position] is NamedPlace){
            return 1
        }
        return 0
    }

    class ViewHolder(binding:VisitedItemBinding):RecyclerView.ViewHolder(binding.root){
        val binding = binding
        fun bind(place:Place){
            binding.model = place

        }
    }

    class NamedViewHolder(binding:VisitedNamedItemBinding):RecyclerView.ViewHolder(binding.root){
        val binding = binding
        fun bind(place:NamedPlace){
            binding.model = place
        }
    }
}

첫번째로 getItemViewType에서 내가 나누고 싶은 조건을 정할 수 있습니다. 저의 경우 같은 items에 있는(Place타입입니다.) 데이터를 NamedPlace로 캐스팅할 수 있는가를 조건으로 정하였습니다. 저와 다르게 같은 데이터 타입에서 특정 변수를 추가할 수도 있습니다.(예를 들어 Place클래스에 viewType이라는 변수를 추가하고 데이터를 삽입하거나 불러올 때 형식을 지정할 수 있습니다)

itemViewType을 정한 뒤 onCreateViewHolder함수에서 바인드할 레이아웃 형태를 정하고 각각 다르게 ViewHolder를 정의합니다. 이때 저의 경우 databinding을 사용하여 레이아웃파일과 ViewHolder를 inflate하였습니다.(LayoutInflater로 inflate해도 무방합니다)

ViewHolder를 create했다면 각각의 itemViewType에 따라 다른 자료형으로 ViewHolder에 바인드하기만 하면 두 가지의 뷰를 가진 RecyclerView를 만들 수 있습니다.(onBindViewHolder)