RecyclerView 편하게 사용하기(Base RecyclerView 만들기)

WonDDak·2022년 10월 16일
1

RecyclerView를 사용하다면 비슷한 형태가 반복되는데 ,
반복되는 코드를 되게 싫어하는 편이라
Base형태로 만들어 상속받아 사용하는 편이다.

BaseViewHolder

/**
 * BaseViewHolder
 * @param ITEM list의 들어가는 item type
 * @param binding viewBinding
 */
abstract class BaseViewHolder<ITEM : Any>(
    val binding: ViewBinding,
) : RecyclerView.ViewHolder(binding.root) {

    abstract fun onBind(item: ITEM) // item Bind
}

먼저 BaseViewHolder이다, ITEM을 Generic으로 받으며,
연결할 뷰를 binding param으로 받는다.

그 뒤 holder에서 bind시켜줄 onBind함수를 구현해준다.

BaseRecyclerAdapter

/**
 * @param ITEM list의 들어가는 item type
 * @param binding viewBinding
 */
abstract class BaseRecyclerAdapter<ITEM : Any, B : ViewBinding>(
) : RecyclerView.Adapter<BaseViewHolder<ITEM>>() {

    open var itemList: MutableList<ITEM> = mutableListOf()// 아이템 리스트 ||기본 empty
    abstract fun initViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<ITEM>

    //아이템 insert
    open fun insertItems(items: List<ITEM>?) {
        this.itemList.run {
            clear()
            itemList.addAll(items ?: emptyList())
        }
        notifyDataSetChanged()
    }

    open fun addItem(getItem: ITEM) {
        val index = itemList.size
        itemList.add(getItem)
        notifyItemInserted(index)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<ITEM> {
        return initViewHolder(parent, viewType)
    }

    override fun getItemCount(): Int = itemList.size

    override fun onBindViewHolder(holder: BaseViewHolder<ITEM>, position: Int) {
        holder.onBind(itemList[position])
    }

    override fun getItemId(position: Int): Long {
        return position.toLong()
    }

}

BaseRecylcerAdapter에서는 ITEM과 B를 제너릭으로 받는다.
그리고 initViewHolder함수 통해 onCreateViewHolder과 연결해준다.


BaseViewBindingRecyclerAdapter

abstract class BaseViewBindingRecyclerAdapter<ITEM : Any, B : ViewBinding>(
    val inflate: (LayoutInflater, ViewGroup?, Boolean) -> B,
) : BaseRecyclerAdapter<ITEM, B>() {
    abstract fun onBindItem(binding: B, item: ITEM) // 아이템 연결

    override fun initViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<ITEM> {
        val binding: B = inflate(LayoutInflater.from(parent.context), parent, false)
        return object : BaseViewHolder<ITEM>(binding) {

            override fun onBind(item: ITEM) {
                this@BaseViewBindingRecyclerAdapter.onBindItem(binding, item)
            }
        }
    }
}

BaseDataBindingRecylcerAdapter

abstract class BaseDataBindingRecyclerAdapter<ITEM : Any, B : ViewBinding>(
    @LayoutRes private val resId: Int,
) : BaseRecyclerAdapter<ITEM, B>() {

    abstract fun onBindItem(binding: B, item: ITEM) // 아이템 연결

    override fun initViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<ITEM> {
        val binding: B = DataBindingUtil.inflate(
            LayoutInflater.from(parent.context),
            resId,
            parent,
            false
        )
        return object : BaseViewHolder<ITEM>(binding) {

            override fun onBind(item: ITEM) {
                this@BaseDataBindingRecyclerAdapter.onBindItem(binding, item)
            }
        }
    }
}

ViewBinding또는 Databinding형태로 바로 연결할수 있게 구현하였다.
기본적으로 viewHolder 을 생성하지 않고 자동으로 BaseViewHolder 을 기반으로 생성해준다

필요하다면, 상속받은 클래스에서 override시켜서 다시 만들어주자.


사용법 예시이다.

class RecipeRecentViewPager :
    BaseDataBindingRecyclerAdapter<Recipe, ItemMainFoodBinding>(R.layout.item_main_food) {
    override fun onBindItem(binding: ItemMainFoodBinding, item: Recipe) {
        binding.recipe = item

    }
}

현재 만들고 있는 앱에서 복사해왔다.

profile
안녕하세요. 원딱입니다.

0개의 댓글