2021. 1. 24. 02:36ใ๐ฑAndroid/๐ฉ๐ป๐ป Android ๊ฐ๋ฐ ์ผ์ง
์ค๋์ ๋ค์๊ณผ ๊ฐ์ ๋ฉํฐ๋ทฐ ํ์ ์ ๋ฆฌ์ฌ์ดํด๋ฌ๋ทฐ๋ฅผ ๊ตฌํํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค !
์ฌ์ด๋ ํ๋ก์ ํธ๋ฅผ ํ๋ฉด์ ๋ฆฌ์ฌ์ดํด๋ฌ๋ทฐ์ ์ฌ๋ฌ itemview๋ฅผ ์ ์ฉํ ์ ์๋ ๋ฐฉ๋ฒ์ ๋ํด ์ฐพ์๋ณด๋ ์ค ๋ฉํฐ๋ทฐ ํ์ ๋ฆฌ์ฌ์ดํด๋ฌ๋ทฐ์ด ์กด์ฌํ๋ ๊ฒ์ ์ฒ์ ์๊ฒ ๋์๋๋ฐ์.
ํ๋์ Adapter๋ฅผ ์ด์ฉํ์ฌ ์ฌ๋ฌ View๋ฅผ ํ์ฉํ ๋ฆฌ์ฌ์ดํด๋ฌ๋ทฐ๋ฅผ ๋ง๋ค ์ ์๋ค๋ ๊ฒ์ ๋ฐฐ์ธ ์ ์์์ต๋๋ค!
๋ฆฌ์ฌ์ดํด๋ฌ๋ทฐ ๊ด๋ จ ๋ค๋ฅธ ํฌ์คํ ์ด ๊ถ๊ธํ์๋ค๋ฉด !? ์๋ ๊ธ์ ๋จผ์ ์ฝ๊ณ ์ค์๋ ๊ฒ ์ข์ต๋๋ค!
๐ RecyclerView ์์ ๋ด๊ธธ Layout ๋ง๋ค์ด์ฃผ๊ธฐ
๊ฐ๋จํ๊ฒ 3๊ฐ๋ฅผ ๋ง๋ค์ด์ฃผ๊ฒ ์ต๋๋ค.
<?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:tools="http://schemas.android.com/tools"
android:paddingHorizontal="20dp"
android:paddingVertical="10dp"
android:background="@color/purple_500"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ImageView
android:id="@+id/img_rv_photo"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@color/black"
android:transitionName="image"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<TextView
android:id="@+id/tv_rv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="์ด๋ฆ"
android:transitionName="name"
android:textStyle="bold"
android:layout_marginLeft="20dp"
android:textSize="24sp"
android:textColor="@color/white"
app:layout_constraintLeft_toRightOf="@id/img_rv_photo"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/tv_rv_age"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="๋์ด"
android:layout_marginTop="10dp"
android:layout_marginLeft="20dp"
android:textSize="18sp"
android:textColor="@color/white"
app:layout_constraintLeft_toRightOf="@id/img_rv_photo"
app:layout_constraintTop_toBottomOf="@id/tv_rv_name"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<?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:tools="http://schemas.android.com/tools"
android:paddingHorizontal="20dp"
android:paddingVertical="10dp"
android:background="@color/purple_500"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ImageView
android:id="@+id/img_rv_photo"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@color/black"
android:transitionName="image"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<TextView
android:id="@+id/tv_rv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="์ด๋ฆ"
android:transitionName="name"
android:textStyle="bold"
android:layout_marginRight="20dp"
android:textSize="24sp"
android:textColor="@color/white"
app:layout_constraintRight_toLeftOf="@id/img_rv_photo"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/tv_rv_age"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="๋์ด"
android:layout_marginTop="10dp"
android:layout_marginRight="20dp"
android:textSize="18sp"
android:textColor="@color/white"
app:layout_constraintRight_toLeftOf="@id/img_rv_photo"
app:layout_constraintTop_toBottomOf="@id/tv_rv_name"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<?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:tools="http://schemas.android.com/tools"
android:paddingHorizontal="20dp"
android:paddingVertical="10dp"
android:background="@color/purple_500"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ImageView
android:id="@+id/img_rv_photo"
android:layout_width="160dp"
android:layout_height="160dp"
android:src="@color/black"
android:transitionName="image"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/tv_rv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="์ด๋ฆ"
android:transitionName="name"
android:textStyle="bold"
android:textSize="24sp"
android:layout_marginVertical="20dp"
android:textColor="@color/white"
app:layout_constraintTop_toBottomOf="@id/img_rv_photo"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
๐ activity_multiview.xml
๋ฉํฐ๋ทฐ ํ์ ์ ๋ฆฌ์ฌ์ดํด๋ฌ๋ทฐ๊ฐ ์กด์ฌํ๋ Activity์ ๋ ์ด์์ ์ ๋๋ค. ๊ฐ๋จํ๊ฒ RecyclerView๋ง ๋ฃ์ด์ฃผ์์ต๋๋ค.
<?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=".recyclerview_basic.MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/rv_profile"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:orientation="vertical"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
๐ data class ๋ง๋ค์ด์ฃผ๊ธฐ
๋ฐ์ดํฐ๋ฅผ ๋ด์ data class๋ฅผ ๋ง๋ค์ด์ฃผ๊ธฐ ์ type์ ๋ฐ๋ผ ์ฝ๊ฒ view๋ฅผ ๊ตฌ๋ณํ๊ธฐ ์ํด MultiMode.kt๋ฅผ ๋ง๋ค์ด ์ฃผ๋๋ก ํ๊ฒ ์ต๋๋ค.
MultiMode.kt
package com.example.recyclerview_ex.recyclerview_multi
const val multi_type1 = 1
const val multi_type2 = 2
const val multi_type3 = 3
MultiData.kt
type์ ๋ฐ๋ผ ๋ค๋ฅธ ViewHolder๋ฅผ ์ง์ ํด์ค์ผ ํ๊ธฐ ๋๋ฌธ์ data class์ type๋ ์ถ๊ฐ๋ก ๋ง๋ค์ด ์ฃผ์์ต๋๋ค.
package com.example.recyclerview_ex.recyclerview_multi
data class MultiData(
val image : Int,
val name : String,
val age : Int,
val type : Int
)
๐MultiViewAdpater ๋ง๋ค๊ธฐ
๋ฉํฐ๋ทฐ ํ์ ์ ๋ฆฌ์ฌ์ดํด๋ฌ๋ทฐ๋ฅผ ์ํ MultiviewAdapter.kt๋ฅผ ๋ง๋ค์ด ์ฃผ๋๋ก ํ๊ฒ ์ต๋๋ค.
์ด์ ์ onCreateViewHolder์ ๊ดํ ์ค๋ช ์ด ํ ๊ฑฐ ๊ฐ์ต๋๋ค.
์๋๋ ๊ธฐ๋ณธ์ ์ ๋ฆฌ์ฌ์ดํด๋ฌ๋ทฐ Adpater์์ ์ฌ์ฉํ๋ onCreateViewHolder ์ ๋๋ค.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = ViewHolder(parent.inflate(R.layout.item_recycler_ex))
์ด๋ viewType์ ๋ฌด์์ผ๊น์?!
viewTpye์ ๋ณ์๋ช ๊ทธ๋๋ก viewType์ ์ํด ๊ตฌ๋ถ๋์ด ๋ค์ด์ค๋ ๊ฐ์ ๋๋ค.
onCreateViewHolder๊ฐ ํธ์ถ ์ getItemViewType(position: Int) : Int ํจ์๋ฅผ ๋จผ์ ํธ์ถํ๋ฉฐ ๋ฆฌํด ๊ฐ์ด ๋๊ฒจ์ง๋ ๊ฒ ์ ๋๋ค.
์๊น ์์์ ๋ง๋ ์ ์ญ ๋ณ์์ธ MultiMode์ ๋ณ์๊ฐ์ data class์ ์ ์ฅํด์ค ์ด์ ๊ฐ ๋ฐ๋ก ์ด๊ฒ ๋๋ฌธ์ ๋๋ค.
override fun getItemViewType(position: Int): Int {
return datas[position].type
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) : RecyclerView.ViewHolder {
val view : View?
return when(viewType) {
multi_type1 -> {
view = LayoutInflater.from(parent.context).inflate(
R.layout.item_recycler_ex,
parent,
false
)
MultiViewHolder1(view)
}
multi_type2 -> {
view = LayoutInflater.from(parent.context).inflate(
R.layout.item_recycler_multi1,
parent,
false
)
MultiViewHolder2(view)
}
else -> {
view = LayoutInflater.from(parent.context).inflate(
R.layout.item_recycler_multi2,
parent,
false
)
MultiViewHolder3(view)
}
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when(datas[position].type) {
multi_type1 -> {
(holder as MultiViewHolder1).bind(datas[position])
holder.setIsRecyclable(false)
}
multi_type2 -> {
(holder as MultiViewHolder2).bind(datas[position])
holder.setIsRecyclable(false)
}
else -> {
(holder as MultiViewHolder3).bind(datas[position])
holder.setIsRecyclable(false)
}
}
}
innerclass๋ก ๋ทฐํ์ ์ ๋ง๋ ViewHolder ๋ง๋ค์ด์ฃผ๊ธฐ
inner class MultiViewHolder1(view: View) : RecyclerView.ViewHolder(view) {
private val txtName: TextView = view.findViewById(R.id.tv_rv_name)
private val txtAge: TextView = view.findViewById(R.id.tv_rv_age)
private val imgProfile: ImageView = view.findViewById(R.id.img_rv_photo)
fun bind(item: MultiData) {
txtName.text = item.name
txtAge.text = item.age.toString()
Glide.with(itemView).load(item.image).into(imgProfile)
}
}
inner class MultiViewHolder2(view: View) : RecyclerView.ViewHolder(view) {
private val txtName: TextView = view.findViewById(R.id.tv_rv_name)
private val txtAge: TextView = view.findViewById(R.id.tv_rv_age)
private val imgProfile: ImageView = view.findViewById(R.id.img_rv_photo)
fun bind(item: MultiData) {
txtName.text = item.name
txtAge.text = item.age.toString()
Glide.with(itemView).load(item.image).into(imgProfile)
}
}
inner class MultiViewHolder3(view: View) : RecyclerView.ViewHolder(view) {
private val txtName: TextView = view.findViewById(R.id.tv_rv_name)
private val imgProfile: ImageView = view.findViewById(R.id.img_rv_photo)
fun bind(item: MultiData) {
txtName.text = item.name
Glide.with(itemView).load(item.image).into(imgProfile)
}
}
๋ทฐํ์ ์ ๋ง๊ฒ ๋ทฐํ๋๋ฅผ ๋ง๋ค์ด ์ ์ง์ ํด์ฃผ์๋ค๋ฉด ์๋ง ์ฝ๊ฒ ๊ตฌํํ์ค ์ ์์ ๊ฒ์ ๋๋ค.
MultiviewAdapter.kt ์ ์ฒด
package com.example.recyclerview_ex.recyclerview_multi
import android.content.Context
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
import com.example.recyclerview_ex.R
class MultiviewAdpater(private val context: Context) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
var datas = mutableListOf<MultiData>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) : RecyclerView.ViewHolder {
val view : View?
return when(viewType) {
multi_type1 -> {
view = LayoutInflater.from(parent.context).inflate(
R.layout.item_recycler_ex,
parent,
false
)
MultiViewHolder1(view)
}
multi_type2 -> {
view = LayoutInflater.from(parent.context).inflate(
R.layout.item_recycler_multi1,
parent,
false
)
MultiViewHolder2(view)
}
else -> {
view = LayoutInflater.from(parent.context).inflate(
R.layout.item_recycler_multi2,
parent,
false
)
MultiViewHolder3(view)
}
}
}
override fun getItemCount(): Int = datas.size
override fun getItemViewType(position: Int): Int {
return datas[position].type
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when(datas[position].type) {
multi_type1 -> {
(holder as MultiViewHolder1).bind(datas[position])
holder.setIsRecyclable(false)
}
multi_type2 -> {
(holder as MultiViewHolder2).bind(datas[position])
holder.setIsRecyclable(false)
}
else -> {
(holder as MultiViewHolder3).bind(datas[position])
holder.setIsRecyclable(false)
}
}
}
inner class MultiViewHolder1(view: View) : RecyclerView.ViewHolder(view) {
private val txtName: TextView = view.findViewById(R.id.tv_rv_name)
private val txtAge: TextView = view.findViewById(R.id.tv_rv_age)
private val imgProfile: ImageView = view.findViewById(R.id.img_rv_photo)
fun bind(item: MultiData) {
txtName.text = item.name
txtAge.text = item.age.toString()
Glide.with(itemView).load(item.image).into(imgProfile)
}
}
inner class MultiViewHolder2(view: View) : RecyclerView.ViewHolder(view) {
private val txtName: TextView = view.findViewById(R.id.tv_rv_name)
private val txtAge: TextView = view.findViewById(R.id.tv_rv_age)
private val imgProfile: ImageView = view.findViewById(R.id.img_rv_photo)
fun bind(item: MultiData) {
txtName.text = item.name
txtAge.text = item.age.toString()
Glide.with(itemView).load(item.image).into(imgProfile)
}
}
inner class MultiViewHolder3(view: View) : RecyclerView.ViewHolder(view) {
private val txtName: TextView = view.findViewById(R.id.tv_rv_name)
private val imgProfile: ImageView = view.findViewById(R.id.img_rv_photo)
fun bind(item: MultiData) {
txtName.text = item.name
Glide.with(itemView).load(item.image).into(imgProfile)
}
}
}
๐ MultiViewActivity.kt
๋ฆฌ์ฌ์ดํด๋ฌ๋ทฐ์ Adpater๋ฅผ ์ฐ๊ฒฐํด์ฃผ๊ณ dataclass์ ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐํด์ฃผ๋๋ก ํ๊ฒ ์ต๋๋ค.
์๋ ์ฝ๋๋ ๋ฆฌ์ฌ์ดํด๋ฌ๋ทฐ ๋ง๋๋ ๊ณผ์ ์์ ๋ค๋ฃฌ ๋ด์ฉ์ด๋ฏ๋ก ์ค๋ช ์ ์๋ตํ๋๋ก ํ๊ฒ ์ต๋๋ค.
package com.example.recyclerview_ex.recyclerview_multi
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.recyclerview_ex.HorizontalItemDecorator
import com.example.recyclerview_ex.R
import com.example.recyclerview_ex.VerticalItemDecorator
import kotlinx.android.synthetic.main.activity_main.*
class MultiviewActivity : AppCompatActivity() {
lateinit var multiAdapter: MultiviewAdpater
val datas = mutableListOf<MultiData>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_multiview)
initRecycler()
}
private fun initRecycler() {
multiAdapter = MultiviewAdpater(this)
rv_profile.adapter = multiAdapter
rv_profile.addItemDecoration(VerticalItemDecorator(10))
rv_profile.addItemDecoration(HorizontalItemDecorator(10))
datas.apply {
add(MultiData(image = R.drawable.profile1, name = "mary", age = 24, multi_type3))
add(MultiData(image = R.drawable.profile3, name = "jenny", age = 26, multi_type2))
add(MultiData(image = R.drawable.profile2, name = "jhon", age = 27, multi_type1))
add(MultiData(image = R.drawable.profile5, name = "ruby", age = 21, multi_type2))
add(MultiData(image = R.drawable.profile4, name = "yuna", age = 23, multi_type3))
multiAdapter.datas = datas
multiAdapter.notifyDataSetChanged()
}
}
}
๋ - ์๋ ํ๋ฉด๊ณผ ๊ฐ์ ๋ค์ํ view๊ฐ ์ฌ์ฉ๋ ๋ฉํฐ๋ทฐ ํ์ ์ ๋ฆฌ์ฌ์ดํด๋ฌ๋ทฐ๋ฅผ ์์ฑํ์ค ์ ์์ต๋๋ค : )
๋ค์ ํฌ์คํ ์๋ ๋ฆฌ์ฌ์ดํด๋ฌ๋ทฐ ๋ง์ง๋ง ์๋ฆฌ์ฆ์ธ RecyclerView Swipe ์ ๋ํ ๊ธ์ ์จ๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค !
๋๊น์ง ์ฝ์ด๋ด์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค!
'๐ฑAndroid > ๐ฉ๐ปโ๐ป Android ๊ฐ๋ฐ ์ผ์ง' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Android] Github Action์ ์ด์ฉํ์ฌ apk ํ์ผ Slack์ผ๋ก ๋ด๋ณด๋ด๊ธฐ (3) | 2021.05.06 |
---|---|
[Android/Kotlin] RecyclerView Animation ํ์ฉํ๊ธฐ (0) | 2021.01.22 |
[Android/Kotlin] RecyclerView ํด๋ฆญ ์ด๋ฒคํธ ์ ์ฉํ๊ธฐ (13) | 2021.01.22 |