2021.05.15 - [Android] - [Android] RecyclerView (1) - Multi ViewHolder
기존 포스팅이 존재하지만, 기존 포스팅에선 같은 모델에서 type에 따라 나누는 방식을 사용했지만
보통 RecyclerView를 사용할 때 다양한 Model을 사용하기 때문에
ViewHolder별로 다른 DTO를 MultiViewHolder로 보이는 방식을 사용해 보겠습니다
코드를 보기 전에 이번 포스팅에서 사용할 Sealed Class에 대해 알아보자면,
Sealed Class
abstract class로 자신을 상속받는 하위클래스들을 가질 수 있습니다.
상속을 보다 효율적으로 관리하고, 제한된 클래스의 계층구조를 나타내고 컴파일 시 SubClass들을 알 수 있습니다
Enum Class와 비슷한 형태이지만, Enum class는 아래와 같은 제약사항이 있습니다
📍 Enum의 제약사항
• Single Instance
• 서브 클래스 생성 불가
• 생성 후 속성값 변경 불가
하지만, Sealed Class는 위의 제약사항들에 영향을 받지 않습니다
📌 MultipleViewHolder
위와 같이 하나의 RecyclerView를 Top, Items로 사용한다고 가정하겠습니다
1. DTO 생성하기
• sealed class를 사용해서 각 ViewHolder에서 사용될 DTO를 정의합니다
• 각 TYPE을 구분하기 위해 ZERO, ONE을 정의합니다
sealed class DTO {
data class Top(val main: String) : DTO()
data class Item(val img: Int, val title: String, val msg: String) : DTO()
}
object TYPE{
const val ZERO = 0
const val ONE = 1
}
2. 각각 ViewHolder 생성하기
• 각 ViewHolder별로 생성될 UI와 Data를 연결합니다 (with. DataBinding)
class MainTop(val binding: MainTopBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: DTO.Top) {
binding.tvTxt.text = item.main
}
}
class MainSecond(val binding: MainSecondBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: DTO.Item) = with(binding) {
tvTxt.text = item.title
imgCon.background = ContextCompat.getDrawable(root.context, item.img)
tvComment.text = item.msg
}
}
3. RecyclerView Adapter 생성
1) create
• viewType별로 각각의 Holder를 생성합니다
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
when (viewType) {
TYPE.ZERO -> {
return MainTop(
MainTopBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
TYPE.ONE -> {
return MainSecond(
MainSecondBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
else -> {
throw Exception("onCreateViewHolder Error")
}
}
}
2) bind
• ViewHolder에 데이터를 결합시킵니다
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is MainTop -> {
holder.bind(itemList[position] as DTO.Top)
}
is MainSecond -> {
holder.bind(itemList[position] as DTO.Item)
}
}
}
3) addItem
• ViewController로부터 데이터를 받는 부분입니다
fun addTops(item: DTO.Top) {
this.itemList.add(item)
}
@SuppressLint("NotifyDataSetChanged")
fun addItems(item: List<DTO.Item>) {
this.itemList.addAll(item)
notifyDataSetChanged()
}
4. Activity에서 Recycler 생성 및 어댑터 연결
• Adapter를 생성하고 3에서 생성한 함수를 통해 데이터를 전달합니다
private fun initView() = with(binding) {
recyclerView.adapter = MainAdapter()
(recyclerView.adapter as MainAdapter).addTops(DTO.Top("👍🏻 List of hobbies"))
val items = arrayOf(
DTO.Item(R.drawable.ic_and, "Android", "Android Develop"),
DTO.Item(R.drawable.ic_music, "Music", "K-Pop"),
DTO.Item(R.drawable.ic_swim, "Swim", "Enjoy Summer")
)
(recyclerView.adapter as MainAdapter).addItems(items.toList())
}
포스팅에선 Activity에서 데이터를 직접 생성했지만, API와 통신할때도 마찬가지고 위와 같은 구조를 사용하시면 됩니다
RecyclerView를 사용하다보면 거진 Multi ViewHolder를 사용할텐데 sealed class를 사용하니 한결 구조화된 느낌이 들었습니다
전체 코드는 아래 GitHub에 있습니다 😀
https://github.com/eunie9498/MultipleViewHolder
궁금하신 점이나 의견이 있으시면 댓글 부탁드립니다 감사합니다 😊
'📱 Android' 카테고리의 다른 글
[Android] Custom Spinner (0) | 2022.08.09 |
---|---|
[Android] Custom Rating Bar (0) | 2022.08.04 |
[Android] Fragment LifeCycle (0) | 2022.07.06 |
[Android] 4대 Component (0) | 2022.07.05 |
[Android] Activity LifeCycle 🧐 (0) | 2022.07.03 |