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