RecyclerView View Type

sumi Yoo·2022년 10월 7일
0

RecyclerView View Type

RecyclerView를 만들때 구분해서 만들 수 있다. 예를 들면, 메신저의 채팅 목록이다.

구현 방법

기존에 포스팅 했던 리사이클러뷰와 크게 다르지 않다. 두 가지 타입으로 나누어서 구현을 했다. 타이틀이 적혀있는 header 부분과 내용이 있는 content 부분으로 나누었다.

이제 코드를 나누어서 봐보자.

MainViewData

sealed class MainViewData(open val type: Int) {
    data class HeaderData(
        val title: String,
        override val type: Int
    ) : MainViewData(type)

    data class ContentData(
        val storeItems: StoreItem,
        override val type: Int
    ) : MainViewData(type)
}

먼저, view type을 구분하기 쉽게 sealed class로 묶어주었다. 둘 다 필요한 데이터와 타입 정보를 가지고 있다.

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return when (viewType) {
            HEADER_TYPE -> {
                HeaderViewHolder(
                    ItemHeaderBinding.inflate(
                        LayoutInflater.from(parent.context),
                        parent,
                        false
                    )
                )
            }
            else -> {
                ContentViewHolder(
                    ItemContentBinding.inflate(
                        LayoutInflater.from(parent.context),
                        parent,
                        false
                    )
                )
            }
        }
    }

뷰홀더를 생성할 때 타입에 따라 구분해서 생성해줘야 한다. 인자로 넘어오는 viewType으로 구분해서 뷰홀더를 생성해준다. 이때 getItemViewType() 함수를 오버라이딩 해줘야 하는데, 여기서 반환하는 값이 onCreateViewHolder의 인자로 넘어간다. 따라서 타입별로 구분할 수 있다.

override fun getItemViewType(position: Int): Int {
        return dataList.value?.get(position)?.type ?: 0
    }

참고로, 아래 함수의 반환값이 0이 되면 화면에 아무것도 보이지 않게 된다.

override fun getItemCount() = dataList.value?.size ?: 0

onCreateViewHolder에서 반환했던 값이 이 함수의 viewHolder 인자로 넘어오는 것 같다. 이때도, 타입별로 뷰 홀더를 캐스팅 해주고 바인딩 해준다.

override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) {
        when (val mainViewData = dataList.value?.get(position) ?: 0) {
            is MainViewData.HeaderData -> {
                (viewHolder as HeaderViewHolder).bind(mainViewData)
            }
            is MainViewData.ContentData -> {
                (viewHolder as ContentViewHolder).bind(mainViewData)
            }
        }
    }

각각의 뷰 홀더 클래스를 정의해주고, 필요한 로직을 구현해주면 된다. HeaderViewHolder에서는 단순히 textView에 내용을 적어주기만 한다.

class HeaderViewHolder(binding: ItemHeaderBinding) : RecyclerView.ViewHolder(binding.root) {

        private val title = binding.tvTitle

        fun bind(item: MainViewData.HeaderData) {
            title.text = item.title
        }
    }

MainViewAdapter (전체코드)

class MainViewAdapter(private val dataList: LiveData<MutableList<MainViewData>>) :
    RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return when (viewType) {
            HEADER_TYPE -> {
                HeaderViewHolder(
                    ItemHeaderBinding.inflate(
                        LayoutInflater.from(parent.context),
                        parent,
                        false
                    )
                )
            }
            else -> {
                ContentViewHolder(
                    ItemContentBinding.inflate(
                        LayoutInflater.from(parent.context),
                        parent,
                        false
                    )
                )
            }
        }
    }

    override fun getItemViewType(position: Int): Int {
        return dataList.value?.get(position)?.type ?: 0
    }

    override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) {
        when (val mainViewData = dataList.value?.get(position) ?: 0) {
            is MainViewData.HeaderData -> {
                (viewHolder as HeaderViewHolder).bind(mainViewData)
            }
            is MainViewData.ContentData -> {
                (viewHolder as ContentViewHolder).bind(mainViewData)
            }
        }
    }

    override fun getItemCount() = dataList.value?.size ?: 0

    class ContentViewHolder(binding: ItemContentBinding) : RecyclerView.ViewHolder(binding.root) {

        private val img = binding.vImg
        private val title = binding.tvTitle
        private val body = binding.tvBody
        private val someId = binding.tvSomeId
        private val someIdLine = binding.tvSomeIdLine
        private val eventContainer = binding.rlEvent
        private val lanchingContainer = binding.rlLanching
        private val regexTitle = Regex("(?<=\\] )(.*?)(?= \\d)")

        fun bind(item: MainViewData.ContentData) {
            title.text = regexTitle.find(item.storeItems.title)?.value ?: ""
            body.text = item.storeItems.description
            someId.text = item.storeItems.s_price

            if (item.storeItems.n_price != null) {
                someIdLine.text = "${item.storeItems.n_price}원"
                someIdLine.paintFlags = someIdLine.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
            }
            if (item.storeItems.badge.isNullOrEmpty()) {
                eventContainer.visibility = View.GONE
                lanchingContainer.visibility = View.GONE
            } else if (item.storeItems.badge.size == 2) {
                eventContainer.visibility = View.VISIBLE
                lanchingContainer.visibility = View.VISIBLE
            } else if (item.storeItems.badge[0] == "이벤트특가") {
                eventContainer.visibility = View.VISIBLE
                lanchingContainer.visibility = View.GONE
            } else {
                eventContainer.visibility = View.GONE
                lanchingContainer.visibility = View.VISIBLE
            }
        }
    }

    class HeaderViewHolder(binding: ItemHeaderBinding) : RecyclerView.ViewHolder(binding.root) {

        private val title = binding.tvTitle

        fun bind(item: MainViewData.HeaderData) {
            title.text = item.title
        }
    }

    companion object {
        const val HEADER_TYPE = 1
        const val CONTENT_TYPE = 2
    }
}

어댑터는 모두 구현이 되었고, 이제 메인 액티비티에 연결만 해주면 된다.

MainActivity

binding.rvMain.adapter = MainViewAdapter(viewDataList)

0개의 댓글

관련 채용 정보