리사이클러 뷰의 레이아웃을 관리해주는 Layout Manager
는 크게 3가지가 있다.
LinearLayoutManager
: 수평, 수직으로 뷰홀더들을 보여준다.GridLayoutManager
: 격자 형식으로 뷰홀더들을 보여준다.StaggeredGridLayoutManager
: 높이가 불규칙한 격자형식.
(반응형 매니저인 FlexBoxLayoutManager
이 있지만 위의 세개가 많이 쓰인다)
팀프로젝트를 진행하며 선택과제로 앱구동중 원하는 경우 레이아웃을 변경하는 과제를 구현해보았다.
특정 버튼을 클릭하면 레이아웃이 격자형과 리스트형으로 변경되도록 만들었다.
출처 - [Android] RecyclerView animated transition between Grid and List layouts.
리사이클러 뷰를 생성한 뒤 레이아웃 매니저를 등록한다. 출처페이지의 경우 GridLayout Manager
를 사용 spanCount
를 이용해 레이아웃의 변경을 구현했기에 GridLayoutManager
를 사용해 구현해보았다.
layoutManager = GridLayoutManager(context, 1)
with(binding.recyclerViewContact) {
itemAnimator = null
layoutManager = layoutManager
adapter = listAdapter
}
GridLayoutManager
에 span count
를 1로 지정하면 한라인에 생성되는 아이템이 1개뿐이기때문에 LinearLayoutManager
를 사용한 것과 같이 구현이 가능하다.
초기에는 리스트 형태로 리사이클러 뷰를 생성해주고 버튼이 눌릴때 span count
를 변경해 레이아웃을 변경하고, 어댑터를 다시 연결해준다.
with(layoutManager) {
if (spanCount == 1) {
spanCount = 3
} else {
spanCount = 1
}
}
binding.recyclerViewContact.layoutManager = layoutManager
레이아웃을 변경할 준비가 끝나면 이제 레이아웃별로 다른 아이템이 출력되어야 하기 때문에 Adapter
에서 뷰홀더를 생성하고 span count
에 따라 다른 뷰홀더를 출력할 수 있도록 코드를 바꿔준다.
// 레이아웃 매니저를 생성자로 받아야 span conunt를 체크할 수 있다.
class ContactListAdapter(private val layoutManager: GridLayoutManager) :
ListAdapter<ContactItems, RecyclerView.ViewHolder>(diffUtil) {
// 2가지 타입의 뷰홀더 준비 (리니어, 그리드)
class ContentGridItemViewHolder(binding: ItemContactRecyclerViewGridBinding) :
RecyclerView.ViewHolder(binding.root) { ... }
class ContentsViewHolder(binding: ItemContactRecyclerViewBinding) :
RecyclerView.ViewHolder(binding.root), ContactItemViewHolder { ... }
.
.
.
// 뷰타입 생성시 span count에 따라 다른 뷰타입 생성
override fun getItemViewType(position: Int): Int {
val item = getItem(position)
val span = layoutManager.spanCount
if (item is ContactItems.Contents && span == 1) {
return TYPE_CONTENT_LIST
}
if (item is ContactItems.Contents && span > 1) {
return TYPE_CONTENT_GRID
}
throw IllegalArgumentException("Invaild span count")
}
// 뷰타입에 따라 리스트와 그리드 각각 뷰홀더를 생성한다.
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
if (viewType == TYPE_CONTENT_LIST) {
return ContentsViewHolder(ItemContactRecyclerViewBinding.inflate(inflater, parent,false))
}
if (viewType == TYPE_CONTENT_GRID) {
return ContentGridItemViewHolder(ItemContactRecyclerViewGridBinding.inflate(inflater, parent, false))
}
throw IllegalArgumentException("Invalid view type")
}
// 뷰홀더에 내용을 구현 (인터페이스를 사용해 두 타입 모두 동시에 구현되도록 했다)
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val item = getItem(position)
if (item is ContactItems.Contents) { ... }
}
왜 자꾸 늦게자는거지...?
자야하는데....
못자겠어... 너무재미있다..