일반적인 리사이클러뷰는 하나의 뷰형태만 보여주고 데이터만 달라지지만,
리사이클러뷰 멀티뷰타입을 사용하면 다수의(다른) 뷰형태를 가지는 아이템을 보여줄 수 있다
이런식으로 멀티뷰타입을 통해서 구현하면 아이템들을 다르게 보여줄 수 있다
# 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
'Android > Android 핵심기술' 카테고리의 다른 글
[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 |