Android - ViewType(뷰타입)

2024. 7. 18. 11:43[개발]/Kotlin 활용 앱 개발

# 개념

- 하나의 RecyclerView 안에 여러 Type의 viewHolder가 섞여있는 경우(광고 등)

 

# 사용 방법

1) 표시할 아이템들의 데이터 모델을 정의(보통 sealed class로 정의)

2) getItemViewType(int position) 메서드를 오버라이드 - 각 아이템의 위치에 따라 해당 아이템의 뷰 타입 반환

3) onCreateViewHolder(ViewGroup parent, int viewType) 메서드를 오버라이드 - 뷰 타입에 맞는 ViewHolder 생성

4) onBindViewHolder(RecyclerView.ViewHolder, int position) 메서드를 오버라이드 - ViewHolder에 데이터 바인딩

5) 각 뷰 타입에 해당하는 ViewHolder 클래스를 정의 - RecyclerView.ViewHolder를 상속 / 각 뷰 타입에 맞는 레이아웃과 바인딩 로직 포함 

sealed class ListItem {
    data class HeaderItem(val title: String) : ListItem()
    data class ContentItem(val content: String) : ListItem()
    data class AdItem(val content: String) : ListItem()
}
class MyListAdapter : ListAdapter<ListItem, RecyclerView.ViewHolder>(DIFF_CALLBACK) {

    companion object {
        private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<ListItem>() {
            override fun areItemsTheSame(oldItem: ListItem, newItem: ListItem): Boolean {
                return oldItem == newItem 
            }

            override fun areContentsTheSame(oldItem: ListItem, newItem: ListItem): Boolean {
                return oldItem == newItem
            }
        }

        private const val TYPE_HEADER = 0
        private const val TYPE_CONTENT = 1
        private const val TYPE_AD = 2
    }

    override fun getItemViewType(position: Int): Int {
        return when (getItem(position)) {
            is ListItem.HeaderItem -> TYPE_HEADER
            is ListItem.ContentItem -> TYPE_CONTENT
            is ListItem.AdItem -> TYPE_AD
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return when (viewType) {
            TYPE_HEADER -> HeaderViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_header, parent, false))
            TYPE_CONTENT -> ContentViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_content, parent, false))
            else -> throw IllegalArgumentException("Invalid view type")
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        when (val item = getItem(position)) {
            is ListItem.HeaderItem -> (holder as HeaderViewHolder).bind(item)
            is ListItem.ContentItem -> (holder as ContentViewHolder).bind(item)
            is ListItem.AdItem -> (holder as AdViewHolder).bind(item)
        }
    }

    class HeaderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(item: ListItem.HeaderItem) {
            // 헤더 아이템 바인딩 로직
        }
    }

    class ContentViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(item: ListItem.ContentItem) {
            // 콘텐츠 아이템 바인딩 로직
        }
    }
    
    class AdViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(item: ListItem.ContentItem) {
            // 콘텐츠 아이템 바인딩 로직
        }
    }
}