RecyclerView ViewType에 따라 뷰화면 변경하는 예제
예전에 솝트하면서 전체게시판을 구현할때, viewType 쓰는 방법을 처음 배웠다.
오랜만에 다시해보고 정리하기 ![]()

1.viewType에 따라 보여질 레이아웃 만들기
위에 보이는 레이아웃은 1) 가운데 TextView 하나 있는 레이아웃 2) 왼쪽에 몰려있는 레이아웃 3) 오른쪽에 몰려있는 레이아웃 총 세가지다.
item_center.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="20dp"
android:text="TextView"
android:textSize="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
item_left.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ImageView android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@mipmap/ic_launcher_round" />
<TextView android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="20dp"
android:text="TextView"
app:layout_constraintLeft_toRightOf="@id/imageView"
app:layout_constraintTop_toTopOf="parent" />
<TextView android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:text="TextView"
app:layout_constraintLeft_toRightOf="@id/imageView"
app:layout_constraintTop_toBottomOf="@id/name" />
</androidx.constraintlayout.widget.ConstraintLayout>
item_right.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ImageView android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:layout_marginTop="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@mipmap/ic_launcher_round" />
<TextView android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:layout_marginTop="20dp"
android:text="TextView"
app:layout_constraintRight_toLeftOf="@id/imageView"
app:layout_constraintTop_toTopOf="parent" />
<TextView android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp"
android:text="TextView"
app:layout_constraintRight_toLeftOf="@id/imageView"
app:layout_constraintTop_toBottomOf="@id/name" />
</androidx.constraintlayout.widget.ConstraintLayout>
2.레이아웃에 넣을 data 만들기
겉으로 나타나는 사진, 이름 , 내용 그리고 구분하기 위해 필요한 viewType 을 넣어 data를 만들어준다.
DataItem
package com.example.multipleviewtypetest
class DataItem {
var content=""
var name = ""
var picture = ""
var viewType = 0
constructor(content:String, name: String?="", picture : String?="",viewType:Int){
this.content = content
if (name != null) {
this.name = name
}
if (picture != null) {
this.picture = picture
}
this.viewType = viewType
}
}
3.Adapter와 ViewHolder만들기
리싸이클러뷰를 나타내기 위해서는 Adapter와 ViewHolder가 필요한건 동일하지만 각각 다른 레이아웃을 나타내려면, viewType을 사용해야한다.
//viewType에 따라 구분해주기 위해 필요, 상수로 선언해줌 ! companion object -> java의 static과 유사
companion object{
const val LEFT_CONTENT = 0
const val RIGHT_CONTENT = 1
const val CENTER_CONTENT = 2
}
동일한 레이아웃의 리싸이클러뷰를 만들때, Adapter의 onCreateViewHolder에서 viewType을 본적이 있을것이다. 이 viewType은 getItemViewType이라는 메소드에서 return 해주는 viewType이다.
getItemViewType이라는 함수를 오버라이드 한뒤, 아까 만들어둔 DataItem의 viewType을 return 해서 이걸로 구분해줘야한다. ![]()
override fun getItemViewType(position: Int): Int {
//DataItem타입의 arrayList , 각 position의 viewType에 따라서 레이아웃을 다르게 해줌
return myDataList[position].viewType
}
onCreateViewHolder에서는 만들어둔 item의 layout을 inflate 해서 viewHolder의 매개변수로 넘겨준다.
아까 세개의 item 레이아웃을 만들었으니, viewType에 따라 3가지 ViewHolder를 만들어준다.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
var view : View
return when (viewType) {
CENTER_CONTENT -> {
view = inflater.inflate(R.layout.item_center,parent,false)
CenterViewHolder(view)
} LEFT_CONTENT -> {
view = inflater.inflate(R.layout.item_left,parent,false)
LeftViewHolder(view)
} else -> {
view = inflater.inflate(R.layout.item_right,parent,false)
RightViewHolder(view)
} }}
그다음 onBindViewHolder에서 holder의 종류에 따라 bind를 해준다.
여기서 set을 해줘도 되지만, 나는 viewHolder에 bind함수를 만들어 set해줬다.
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is CenterViewHolder -> {
holder.bind(myDataList[position])
} is LeftViewHolder -> {
holder.bind(myDataList[position])
} else -> { // 무슨 viewHolder인지 제대로 안정해줬으니까, as로 정해주기
(holder as RightViewHolder).bind(myDataList[position])
} }}
그다음 각 ViewHolder에서 findViewById를 사용해서 set할 아이템들을 찾아주고, adapter 에서 호출했던 bind 함수안에서 데이터를 set해주면 된다.
class CenterViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) {
val content: TextView = itemView.findViewById(R.id.content)
fun bind(dataItem:DataItem){
content.text = dataItem.content
}
}
class LeftViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) {
val content: TextView = itemView.findViewById(R.id.content)
val name: TextView = itemView.findViewById(R.id.name)
val image: ImageView = itemView.findViewById(R.id.imageView)
fun bind(dataItem:DataItem){
content.text = dataItem.content
name.text= dataItem.name
Glide.with(image.context).load(dataItem.picture).override(300,300).into(image)
}}
class RightViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) {
val content: TextView = itemView.findViewById(R.id.content)
val name: TextView = itemView.findViewById(R.id.name)
val image: ImageView = itemView.findViewById(R.id.imageView)
fun bind(dataItem:DataItem){
content.text = dataItem.content
name.text= dataItem.name
Glide.with(image.context).load(dataItem.picture).override(300,300).into(image)
}}
MyAdapter.kt
package com.example.multipleviewtypetest
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
class MyAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder> {
//viewType에 따라 구분해주기 위해 필요, 상수로 선언해줌 ! companion object -> java의 static과 유사
companion object{
const val LEFT_CONTENT = 0
const val RIGHT_CONTENT = 1
const val CENTER_CONTENT = 2
} private var myDataList = arrayListOf<DataItem>()
constructor(dataList:ArrayList<DataItem>?)
{ if (dataList != null) {
this.myDataList = dataList
}
}
override fun getItemViewType(position: Int): Int {
//DataItem타입의 arrayList , 각 position의 viewType에 따라서 레이아웃을 다르게 해줌
return myDataList[position].viewType
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
var view : View
return when (viewType) {
CENTER_CONTENT -> {
view = inflater.inflate(R.layout.item_center,parent,false)
CenterViewHolder(view)
} LEFT_CONTENT -> {
view = inflater.inflate(R.layout.item_left,parent,false)
LeftViewHolder(view)
} else -> {
view = inflater.inflate(R.layout.item_right,parent,false)
RightViewHolder(view)
} } }
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is CenterViewHolder -> {
holder.bind(myDataList[position])
} is LeftViewHolder -> {
holder.bind(myDataList[position])
} else -> { // 무슨 viewHolder인지 제대로 안정해줬으니까, as로 정해주기
(holder as RightViewHolder).bind(myDataList[position])
} } }
override fun getItemCount(): Int {
return myDataList.size
}
}
class CenterViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) {
val content: TextView = itemView.findViewById(R.id.content)
fun bind(dataItem:DataItem){
content.text = dataItem.content
}
}
class LeftViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) {
val content: TextView = itemView.findViewById(R.id.content)
val name: TextView = itemView.findViewById(R.id.name)
val image: ImageView = itemView.findViewById(R.id.imageView)
fun bind(dataItem:DataItem){
content.text = dataItem.content
name.text= dataItem.name
Glide.with(image.context).load(dataItem.picture).override(300,300).into(image)
}}
class RightViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) {
val content: TextView = itemView.findViewById(R.id.content)
val name: TextView = itemView.findViewById(R.id.name)
val image: ImageView = itemView.findViewById(R.id.imageView)
fun bind(dataItem:DataItem){
content.text = dataItem.content
name.text= dataItem.name
Glide.with(image.context).load(dataItem.picture).override(300,300).into(image)
}}
4. 리싸이클러뷰 adapter설정 및 데이터 넣기
리싸이클러뷰가 포함된 레이아웃을 만들어준다.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView android:id="@+id/rv_chatting"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
만들어둔 리싸이클러뷰에 레이아웃 메니저와 어댑터를 설정해주고, 데이터들을 추가시키면 끝 !
MainActivity.kt
package com.example.multipleviewtypetest
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.multipleviewtypetest.MyAdapter.Companion.CENTER_CONTENT
import com.example.multipleviewtypetest.MyAdapter.Companion.LEFT_CONTENT
import com.example.multipleviewtypetest.MyAdapter.Companion.RIGHT_CONTENT
class MainActivity : AppCompatActivity() {
private var dataList = arrayListOf<DataItem>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
addItem()
//리싸이클러뷰에 레이아웃 매니저, 어댑터 설정해주기
val rvChatting = findViewById<RecyclerView>(R.id.rv_chatting)
val layoutManager = LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false)
rvChatting.layoutManager = layoutManager
//아이템 추가한 리스트 Adapter에 넘겨주기
rvChatting.adapter = MyAdapter(dataList)
}
//리싸이클러뷰 아이템 추가
private fun addItem(){
dataList.add(DataItem("사용자1님이 입장하셨습니다.",null,"",CENTER_CONTENT))
dataList.add(DataItem("사용자2님이 입장하셨습니다.",null,"",CENTER_CONTENT))
dataList.add(DataItem("안녕하세요","사용자1","https://image.freepik.com/free-photo/friendly-smart-basenji-dog-giving-his-paw-close-up-isolated-white_346278-1626.jpg",LEFT_CONTENT))
dataList.add(DataItem("안녕하세요","사용자2","https://image.freepik.com/free-photo/french-bulldog-dog-breeds-white-polka-dot-black-marble_1150-25345.jpg",RIGHT_CONTENT))
}}
참고
Comments