본문 바로가기

TIL

[TIL] Kotlin RecyclerView ViewType 나누기

[오늘 배운 내용]

-1- RecyclerView ViewType 나누기

만들어 볼 예제

  • RecyclerView의 ViewType을 나누면, RecyclerView의 Item을 내가 원하는 방식으로 타입별로 나누고, 각자 다른 UI를 적용시켜줄 수 있다

 

적용방법

  • 기본적인 RecyclerView는 이미 생성된 상태로 가정함
    • RecyclerView UI, ItemView, Data생성, DataList더미 생성 등등...
  • 기존에 RecyclerView에 적용되는 ItemView와 다른 형식으로 Item을 띄워주고 싶으면 적용할 View XML을 추가로 만들어야 한다. 생성하는 방법은 기존에 ItemView와 동일하게 생성하면 된다

Linear ViewType의 경우 적용되는 ItemView.xml

기존의 Item View

 

Grid ViewType의 경우 적용되는 GridOtemView.xml

새로 추가할 ItemView

 

  • ItemView xml을 생성한 뒤, Adapter.kt로 돌아가서 ViewHolder 를 추가로 생성 해주고, 생성한 VIewHolder에 (1) 에서만든 XML을 바인딩 해주면 된다.
  • ViewHolder를 추가로 생성 하는 이유는 기존에 생성한 ViewHolder는 이미 ItemView.xml과 Binding 되었기 때문에 새로운 ViewHolder를 만들어서 GridItemView.xml과 바인딩 해주어야 한다. 
  • GridItemView의 xml Item들( img, text 등 )의 RecyclerView를 만들 때 생성해둔 Data로 값이 들어가게끔 지정 해주자.

ViewHolder

class RecyclerViewAdapter(private val mItems: MutableList<BrandData>) :
    RecyclerView.Adapter<RecyclerView.ViewHolder>() {

	...
    
    inner class GridViewHolder(binding: ItemViewGridBinding) :
        RecyclerView.ViewHolder(binding.root) {
        val iconImagerView = binding.gridImgLogo
        val name = binding.gridTvBrand
        fun bind(item: BrandData) {
            iconImagerView.setImageResource(item.mImage)
            name.text = item.mName
        }
    }
}

class ViewHolder(binding: ItemViewBinding) : RecyclerView.ViewHolder(binding.root) {
    val iconIamgeView = binding.imgViewIcon
    val name = binding.tvItemName
    val desc = binding.tvItemDesc
}
  •  ViewHolder를 inner class 로 Adapter 클래스 안에서 생성해도 되고, 어뎁터 바깥에서 생성해도 정상적으로 작동한다.

 

  • ViewHolder를 Inner class 로 만드는 것과 outer class로 선언하는 것의 차이점
    • Inner 클래스로 ViewHolder를 선언하게 되면 Adapter 클래스의 데이터나 매서드에 대한 접근이 용이하게 된다. ViewHolder에서 Adapter 클래스의 데이터나 메서드를 직접 사용해야 할 때 유용하다.
    • Outer 클래스는 Adpater 클래스와 독립적으로 동작하며, Adpater 클래스의 멤머 변수나 메서드에 직접 접근할 수 없다. 때문에 ViewHolder가 단순히 UI표시 역할만을 수행해야할 때 사용한다.

 

 

getItemViewType

  • Item의 Viewtype을 어떻게 구별할지 정해준다. 
  • Object 클래스를 이용해서 전역에서 참조할 수 있도록 했다. layoutType은 LayoutManager 를 변경할 때 추가로 사용할 예정.
object ItemViewType {
    var layoutType = 0
    const val LINEAR = 0
    const val GRID = 1
}
class RecyclerViewAdapter(private val mItems: MutableList<BrandData>) :
    RecyclerView.Adapter<RecyclerView.ViewHolder>() {

	...
    
	override fun getItemViewType(position: Int): Int {
        return when (ItemViewType.layoutType) {
            0 -> ItemViewType.LINEAR
            1 -> ItemViewType.GRID
            else -> ItemViewType.LINEAR
        }
    }
    
    ...
    
}

 

onBindViewHolder, onCreateViewHolder

  • onBindViewHolder, onCreateViewHolder 에도 ViewHolder 별로 지정 해주자
class RecyclerViewAdapter(private val mItems: MutableList<BrandData>) :
    RecyclerView.Adapter<RecyclerView.ViewHolder>() {

	...

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        holder.itemView.setOnClickListener {
            itemClick?.onClick(it, position)
        }
        if (ItemViewType.layoutType == 0){
            (holder as ViewHolder)
            holder.iconIamgeView.setImageResource(mItems[position].mImage)
            holder.name.text = mItems[position].mName
            holder.desc.text = mItems[position].mDesc
        } else {
            (holder as GridViewHolder)
            holder.bind(mItems[position])
        }

    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return when (viewType) {
            ItemViewType.GRID -> {
                GridViewHolder(
                    ItemViewGridBinding.inflate(
                        LayoutInflater.from(parent.context), parent,
                        false
                    )
                )
            }

            else -> {
                ViewHolder(
                    ItemViewBinding.inflate(
                        LayoutInflater.from(parent.context),
                        parent,
                        false
                    )
                )
            }

        }
    }

 

 

 

메인Activity

  • 툴바 메뉴에서 각 메뉴 클릭 시 Grid, Linear LayoutManager로 변경되도록 하고, ItemViewType 오브젝트의 LayoutType 을 통해 Adapter 안에도 ViewType 변동이 작용되도록 함.
  • LayoutManager와 ViewType이 바뀌고 나면 리스트를 새로고침 함.
class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    val brandList = mutableListOf<BrandData>()

    init {
        brandList.apply {
        //리스트 추가
        ...
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val myAdapter = RecyclerViewAdapter(brandList)
        binding.recyclerListBrand.adapter = myAdapter
        binding.recyclerListBrand.layoutManager = LinearLayoutManager(this)

        binding.toolbar.setOnMenuItemClickListener {
            when (it.itemId){
                R.id.toolbar_menu_grid -> {
                    ItemViewType.layoutType = 1
                    binding.recyclerListBrand.layoutManager = GridLayoutManager(this,3)
                    myAdapter.notifyDataSetChanged()
                    true
                }
                R.id.toolbar_menu_Linear -> {
                    ItemViewType.layoutType = 0
                    binding.recyclerListBrand.layoutManager = LinearLayoutManager(this)
                    myAdapter.notifyDataSetChanged()
                    true
                }
                else -> {
                    false
                }
            }
        }

 

 

 

 


 

[오늘 복습한 내용]

1. RecyclerView

 

 


[오류,에러 등등]

1. 따로 없었다

 


[느낀 점]

1. 어렵다

 

2. 어려운데 재미가 있어서 시간이 너무 빨리간다. 

 

3. 다리가 젓가락이 되고 있는 것 같다

 

 


[Reference]

 

 

// Viewtype

https://yunaaaas.tistory.com/61