여러 개의 뷰 타입, 즉 리사이클러뷰 내에서 한 개의 뷰 형태만을 랜더링 하는 게 아니라
다수의 뷰 형태를 가지는 객체들을 랜더링하는 방법이다.
총 3개의 다른 뷰 형태를 가지는 리사이클러 뷰를 다뤄볼 것이다. 세 가지 다른 뷰 형태란 아래와 같다.
- 단순 카테고리 명을 표시하는, 텍스트만 있는 뷰
- 글 아래에 이미지가 크게 박힌 뷰
- 사진 오른쪽에 사진 제목과 콘텐츠 내용이 담긴 뷰
Model
랜더링 하고 싶은 데이터를 가지고 있을 클래스
data class Model(val type: Int, val text: String, val data: Int, val contentString: String?) {
companion object {
const val TEXT_TYPE = 0
const val IMAGE_TYPE = 1
const val IMAGE_TYPE_2 = 2
}
}
- 첫 번째 인자 값 : 만든 3가지 형태의 뷰들 중, 어떤 형태의 뷰인지 Int값으로 넘겨줄 것이다. 그 Int은 ViewTypeEnum을 사용한다.
- 두 번째 인자 값 : 텍스트를 입력받을 파라미터. 텍스트 하나만 랜더링 하는 뷰에서는 그 텍스트를, 텍스트 1개 이미지 1개인 뷰에서 텍스트를, 텍스트 2 이미지 1개인 뷰에서는 제목 부분을 담당할 String이다.
- 세 번째 인자 값 : 이미지가 필요한 부라면 이미지를 넣어줄 파라미터.
- 네 번째 인자 값 : 텍스트 2 이미지 1 개인 뷰에서 제목 아래의 콘텐츠 부분의 값을 담당할 String이다.
MainActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
val list = mutableListOf<Model>().apply {
add(Model(Model.TEXT_TYPE, "카테고리 1번!", 0, null))
add(Model(Model.IMAGE_TYPE, "텍스트뷰 아래에 이미지가 있는 뷰타입.", R.drawable.snow, null))
add(Model(Model.IMAGE_TYPE_2, "안녕, 제목부분이 될거야", R.drawable.snow, "내용부분!"))
add(Model(Model.IMAGE_TYPE, "다시 한 번 텍스트 옆에 이미지가 있는 뷰타입", R.drawable.snow, null))
add(Model(Model.IMAGE_TYPE_2, "제목2!!", R.drawable.snow, "사진에 대한 설명?"))
add(Model(Model.TEXT_TYPE, "카테고리 2번!", 0, null))
add(Model(Model.IMAGE_TYPE, "새로운 카테고리 시작!.", R.drawable.snow, null))
add(Model(Model.IMAGE_TYPE, "다음생엔 울창한 숲의 이름모를 나무로 태어나 평화로이 살다가 누군가의 유서가 되고 싶다.", R.drawable.snow, null))
add(Model(Model.IMAGE_TYPE_2, "제목부분.", R.drawable.snow, "내용부분"))
}
val adpater = MultiViewTypeAdapter(list, this)
recycler_view.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false)
recycler_view.adapter = adpater
}
}
MultiViewAdapter
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item, parent, false)
Log.d("tag1" , "onCreateViewHolder")
return MyViewHolder(view)
}
onCreateViewHolder의 인자 중 viewType은 onCreateViewHolder가 호출되기 전, getItemViewType(position: Int): Int함수가 먼저 호출되어 리턴 값이 넘겨진다.
따라서 이 인자로 적절히 뷰 타입을 구분하여 리턴해주면 된다.
뷰 타입을 구분하는 방법이야 여러가지가 있겠지만, 처음 Model객체를 생성할 때부터 첫 번째 인자로 type 값을 구분해서 넣어줬으므로 그대로 넘겨주면 된다.
Adapter 전문
class MultiViewTypeAdapter(private val list: MutableList<Model>) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var totalTypes = list.size
// getItemViewType의 리턴값 Int가 viewType으로 넘어온다.
// viewType으로 넘어오는 값에 따라 viewHolder를 알맞게 처리해주면 된다.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val view: View?
return when (viewType) {
Model.TEXT_TYPE -> {
view = LayoutInflater.from(parent.context).inflate(R.layout.text_type, parent, false)
TextTypeViewHolder(view)
}
Model.IMAGE_TYPE -> {
view = LayoutInflater.from(parent.context).inflate(R.layout.image_type, parent, false)
ImageTypeViewHolder(view)
}
Model.IMAGE_TYPE_2 -> {
view = LayoutInflater.from(parent.context).inflate(R.layout.image_type2, parent, false)
ImageTypeView2Holder(view)
}
else -> throw RuntimeException("알 수 없는 뷰 타입 에러")
}
}
override fun getItemCount(): Int {
return totalTypes
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
Log.d("MultiViewTypeAdapter", "Hi, onBindViewHolder")
val obj = list[position]
when (obj.type) {
Model.TEXT_TYPE -> (holder as TextTypeViewHolder).txtType.text = obj.text
Model.IMAGE_TYPE -> {
(holder as ImageTypeViewHolder).title.text = obj.text
holder.image.setImageResource(obj.data)
}
Model.IMAGE_TYPE_2 -> {
(holder as ImageTypeView2Holder).title.text = obj.text
holder.content.text = obj.contentString
holder.image.setImageResource(obj.data)
}
}
}
// 여기서 받는 position은 데이터의 index다.
override fun getItemViewType(position: Int): Int {
Log.d("MultiViewTypeAdapter", "Hi, getItemViewType")
return list[position].type
}
inner class TextTypeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val txtType: TextView = itemView.findViewById(R.id.title)
}
inner class ImageTypeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val title: TextView = itemView.findViewById(R.id.title)
val image: ImageView = itemView.findViewById(R.id.background)
}
inner class ImageTypeView2Holder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val title: TextView = itemView.findViewById(R.id.titleView)
val content: TextView = itemView.findViewById(R.id.contentView)
val image: ImageView = itemView.findViewById(R.id.imageView2)
}
}
뷰 홀더를 여러 개 만들고, onCreateViewHolder에서 데이터에 따라 그에 맞는 뷰 홀더를 생성해주는 게 전부
사실 뷰 타입을 Model의 compaion object로, 또 숫자로 관리한다는 게 좋진 않지만 여러 개의 뷰 타입을 다루는 리사이클러 뷰를 공부하는 데는 지장이 없다.
Multi View Recycler
wooooooak.github.io/android/2019/04/13/RecyclerView_mutiType/
'Android > Reference' 카테고리의 다른 글
Selector xml (0) | 2020.10.28 |
---|---|
RecyclerView Scroll (0) | 2020.10.28 |
RecyclerView Click Event (0) | 2020.10.28 |
xml에서 opacity(투명도) 넣기 (0) | 2020.10.28 |
screenOrientaion 지정 방법 (0) | 2020.10.28 |