일반적인 리사이클러뷰는 하나의 뷰형태만 보여주고 데이터만 달라지지만,
리사이클러뷰 멀티뷰타입을 사용하면 다수의(다른) 뷰형태를 가지는 아이템을 보여줄 수 있다
이런식으로 멀티뷰타입을 통해서 구현하면 아이템들을 다르게 보여줄 수 있다
# xml
먼저 해당 아이템에 들어갈 레이아웃을 각각 디자인해준다
# 상수정의
enum class를 사용해서 방금만든 뷰타입의 상수를 정의해준다
// enum class로 열거형 클래스로 만들기 (코드 단순, 가독성 up)
enum class MultiViewEnum(val viewType : Int) {
BlUE(0),
LIGHTBLUE(1),
ORANGE(2)
}
# 데이터
들어갈 데이터클래스를 작성해준다
@Parcelize
data class CardData(
val id : Int,
val name : String, //이름
val cardName : String, //카드이름
val number : String, //카드번호
val date : String, //유효기간
val price : Double, //가격
val type : MultiViewEnum // 멀티뷰타입 -> enum class로 만든 클래스 선언
): Parcelable
CardData.kt
싱글톤을 사용해서 데이터소스를 어디서나 편리하게 호출할 수 있도록 만들어준다
// 싱글톤
class DataSource {
companion object{
private var INSTANCE : DataSource? = null
fun getDataSoures() : DataSource{
// DatoSource::class 객체에 lock을 걸어 한번에 한 스레드에서만 실행 되도록 함
return synchronized(DataSource::class) {
// 싱글톤 객체를 한번 호출하고 없으면 DataSource반환, 있으면 생성된 인스턴스 반환
val newInstance = INSTANCE ?: DataSource()
INSTANCE = newInstance
newInstance
}
}
}
// MVVM패턴에서 Model에 해당한다고 볼 수 있음
fun getCardList() : List<CardData>{
// 만들어놓은 데이터클래스 리턴
return CardDataList()
}
}
DataSource.kt
데이터리스트를 만들어서 실제 들어갈 데이터를 넣어준다
fun CardDataList() : ArrayList<CardData>{
return arrayListOf(
CardData(
id = 1,
name = "Juwon",
cardName = "A Debit Card",
number = "2423 3581 9503",
date = "21/27",
price = 3100.30,
MultiViewEnum.BlUE
),
CardData(
id = 2,
name = "Minju",
cardName = "A Hybrid Card",
number = "5423 3581 9503",
date = "07/25",
price = 4100.30,
MultiViewEnum.LIGHTBLUE
),
CardData(
id = 3,
name = "Hemin",
cardName = "A Hi Card",
number = "9423 3581 9503",
date = "23/29",
price = 4170.30,
MultiViewEnum.ORANGE
),
)
}
CardDataList.kt
# Adapter
리사이클러뷰 멀티뷰타입 어댑터의 전체코드는 아래와같다
class CardViewAdpater(var cardList : List<CardData>, private val onClick : (CardData) -> Unit) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
// 레이아웃 연결
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when(viewType){
MultiViewEnum.BlUE.viewType -> {
val binding = RecyclerviewItem1Binding.inflate(inflater, parent, false)
BlueTypeViewHolder(binding)
}
MultiViewEnum.LIGHTBLUE.viewType -> {
val binding = RecyclerviewItem2Binding.inflate(inflater, parent, false)
LightBlueTypeViewHolder(binding)
}
MultiViewEnum.ORANGE.viewType -> {
val binding = RecyclerviewItem3Binding.inflate(inflater, parent, false)
OrangeTypeViewHolder(binding)
}
else -> throw IllegalAccessException("Invalid view type")
}
}
// 아이템 개수 리턴
override fun getItemCount(): Int {
return cardList.size
}
// 멀티뷰타입은 getItemViewType을 오버라이딩 해줘야함
// postion에 따라 어떤 뷰타입을 가져야되는지 연결해줘야함
override fun getItemViewType(position: Int): Int {
return when(position){
0 -> MultiViewEnum.BlUE.viewType
1 -> MultiViewEnum.LIGHTBLUE.viewType
2 -> MultiViewEnum.ORANGE.viewType
else -> throw IllegalAccessException("Invalid view type")
}
}
// 데이터 연결
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val cardlist = cardList[position]
when(holder.itemViewType){
MultiViewEnum.BlUE.viewType -> {
val blueHolder = holder as BlueTypeViewHolder
blueHolder.bind1(cardlist)
// MULTI_VIEWTYPE1 클릭 이벤트 처리 (멀티뷰타입마다 데이터가 완전 다른 경우도 있기 때뮨에 그런경우에는 이렇게 클릭이벤트를 주는게 유용함)
holder.itemView.setOnClickListener {
onClick(cardlist)
}
}
MultiViewEnum.LIGHTBLUE.viewType -> {
val lightBlueHolder = holder as LightBlueTypeViewHolder
lightBlueHolder.bind2(cardlist)
// MULTI_VIEWTYPE2 클릭 이벤트 처리
holder.itemView.setOnClickListener {
onClick(cardlist)
}
}
MultiViewEnum.ORANGE.viewType -> {
val orangeHolder = holder as OrangeTypeViewHolder
orangeHolder.bind3(cardlist)
// MULTI_VIEWTYPE3 클릭 이벤트 처리
holder.itemView.setOnClickListener {
onClick(cardlist)
}
}
}
}
class BlueTypeViewHolder(private val binding : RecyclerviewItem1Binding) : RecyclerView.ViewHolder(binding.root){
fun bind1(card : CardData){
with(binding){
AndersonTv.text = card.name
debitCardTv.text = card.cardName
cardNumberTv.text = card.number
cardDateTv.text = card.date
cardPriceTv.text = "$" + DecimalFormat("#,##0.00").format(card.price).toString()
}
}
}
class LightBlueTypeViewHolder(private val binding : RecyclerviewItem2Binding) : RecyclerView.ViewHolder(binding.root){
fun bind2(card : CardData){
with(binding){
AndersonTv2.text = card.name
debitCardTv2.text = card.cardName
cardNumberTv2.text = card.number
cardDateTv2.text = card.date
cardPriceTv2.text = "$" + DecimalFormat("#,##0.00").format(card.price).toString()
}
}
}
class OrangeTypeViewHolder(private val binding : RecyclerviewItem3Binding) : RecyclerView.ViewHolder(binding.root){
fun bind3(card : CardData){
with(binding){
AndersonTv3.text = card.name
debitCardTv3.text = card.cardName
cardNumberTv3.text = card.number
cardDateTv3.text = card.date
cardPriceTv3.text = "$" + DecimalFormat("#,##0.00").format(card.price).toString()
}
}
}
}
CardViewAdpater.kt
# MainActivity
class MainActivity : AppCompatActivity() {
private val binding : ActivityMainBinding by lazy {
ActivityMainBinding.inflate(layoutInflater)
}
// onClick메소드가 실행되면 람다식이 바로 실행되도록
private val cardAdapter : CardViewAdpater by lazy {
CardViewAdpater(cardList = ArrayList<CardData>()) { card ->
// DetailActivity로 이동하는 함수 실행
adapterClick(card)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
val dataSource = DataSource.getDataSoures().getCardList()
cardAdapter.cardList = dataSource
with(binding.recyclerview) {
adapter = cardAdapter // 리사이클러뷰와 어뎁터 연결
layoutManager = LinearLayoutManager(this@MainActivity)
}
}
private fun adapterClick(card : CardData) {
// DetailActivity로 이동
val intent = Intent(this, DetailActivity::class.java)
val bundle = Bundle().apply {
putParcelable(DetailActivity.EXTRA_CARD, card)
}
intent.putExtras(bundle)
startActivity(intent)
}
}
MainActivity.kt
# DetailActivity
class DetailActivity : AppCompatActivity() {
private val binding: ActivityDetailBinding by lazy {
ActivityDetailBinding.inflate(layoutInflater)
}
// 어디서나 이 키값을 사용할수있게끔 지정!
companion object{
const val EXTRA_CARD : String = "extra_card"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
// Intent로 전달한 데이터 받아옴
val intent = getIntent()
val cardItem = intent?.getParcelableExtra<CardData>(EXTRA_CARD)
with(binding) {
detailCardnameTv.text = "이름: ${cardItem?.name}"
detailCardnunberTv.text = "카드번호: ${cardItem?.number}"
detailDateTv.text = "유효기간: ${cardItem?.date}"
detailPriceTv.text = "가격: $${DecimalFormat("#,##0.00").format(cardItem?.price)}"
}
}
}
DetailActivtiy.kt
# 참고자료
https://yunaaaas.tistory.com/61
[Android/Kotlin] 멀티뷰 타입 RecyclerView 구현하기
오늘은 다음과 같은 멀티뷰 타입의 리사이클러뷰를 구현해보도록 하겠습니다 ! 사이드 프로젝트를 하면서 리사이클러뷰의 여러 itemview를 적용할 수 있는 방법에 대해 찾아보던 중 멀티뷰 타입
yunaaaas.tistory.com
[Android/Kotlin 08] 리사이클러뷰 멀티뷰 타입(Feat. 두개의 아이템 하나의 리스트)
리사이클러뷰 멀티 뷰 타입이란 여러 개의 뷰 타입, 즉 리사이클러뷰 내에서 한 개의 뷰 형태만을 랜더링 하는 게 아니라 다수의 뷰 형태를 가지는 객체들을 랜더링하는 방법입니다. 리사이클러
velog.io
[Android/Kotlin] RecyclerView 각각 아이템마다 클릭 이벤트 설정
GitHub Link네이버 API로 가져온 뉴스들이다.뉴스를 화면에 뿌려주는 것까지는 좋았는데 뉴스를 클릭할 시에 각각 뉴스의 링크로 이동하고 싶은데 어떻게 해야할까?어뎁터 함수내에서 외부와 연결
velog.io
'개발 노트 > Kotlin' 카테고리의 다른 글
[Android/Kotlin] SharedPreferences 사용해서 데이터 저장하기 (0) | 2024.04.30 |
---|---|
[Android/Kotlin] 멀티뷰타입 리사이클러뷰 MVVM패턴으로 수정(Observer Pattern 사용) (0) | 2024.04.29 |
[Android/Kotlin] Text에 밑줄 표시하기 (0) | 2024.04.14 |
[Android/Kotlin] 뒤로가기 버튼 클릭이벤트 구현 OnBackPressedCallback() 사용 (0) | 2024.04.12 |
[Android/Kotlin] 천단위로 콤마 표시하기 (DecimalFormat) (0) | 2024.04.12 |