페이지네이션이란?
페이지네이션은 콘텐츠를 여러 개의 페이지에 나눠서 보여주는 UI이다. 페이지가 하단 포지션에 도달하면 다음 페이지를 호출하여 이전 페이지 아래에 계속 데이터를 붙이는 형태이다.
페이지네이션을 왜 사용하는 가에 대한 의문을 가질 수 있다. 물론 콘텐츠가 적은 경우에는 코드만 길어지므로 굳이 필요 없다고 느끼지만 컨텐츠가 많은 경우에는 상황이 달라진다. 만약 컨텐츠가 갯수가 100개라고 가정해보자. 서버에서 100개의 컨텐츠를 받아올 때의 딜레이, 받은 컨텐츠를 UI에 표현하는 데 걸리는 딜레이, 그리고 유저가 스크롤할 때 퍼포먼스에 대한 버벅임 등 컨텐츠가 많으면 그 만큼 UX적으로 좋지 않아 이때 페이지네이션을 많이 사용한다. 대표적으로 네이버 api, 카카오 api는 페이지네이션을 고려하여 Response를 주고 있다.
페이지네이션을 사용하기 위해서는 크게 2가지의 데이터가 필요하다.
- 총 페이지 수
- 페이지마다의 컨텐츠 리스트
페이지네이션은 대표적으로 RecyclerView에서 많이 사용되지만 ScrollView에서도 사용할 수 있다.
설계
기획서에 가격대별 상품 리스트를 페이지네이션의 형태로 만들어 달라고 하였다.
- 페이지네이션 Data Class
앞서 언급했듯이 필수적으로 필요한 총 페이지 수, 페이지마다 콘텐츠 리스트를 포함한 데이터 클래스를 생성한다.
@Parcelize
data class Gift(
@SerializedName("category")
val categoryId: String,
@SerializedName("printName")
val categoryName: String,
@Expose
@SerializedName("totalCount")
val totalCount: Int,
@Expose
@SerializedName("pageCount")
val pageCount: Int,
@Expose
@SerializedName("itemList")
val giftList: List<GiftInfoModel>?
) : Parcelable
- totalCount : 총 페이지 수
- pageCount : 현재 페이지
- itemList : 컨텐츠 리스트
페이지네이션 할 때마다 서버에서부터 추가로 받는 데이터 List<GiftInfoModel>이다. 그러면 호출할 때마다 새로 받은 리스트를 기존 리스트의 마지막 인덱스 다음에 계속 추가한다.
- 페이지네이션 로직 설계
페이지네이션에서 가장 핵심인 부분은 스크롤이 하단 포지션에 도달했느냐 이다. 사용자가 스크롤을 하는 도중에 새로운 리스트를 호출해 보리면 UX면에서 버벅거림으로 느껴질 수 있다. 따라서 스크롤이 하단 포지션에 도달했을 때 다음 페이지를 호출할 수 있도록 설계해야 한다.
fun onRecyclerViewScrollListener(detectListenerRecyclerView: RecyclerViewScrollDetectListener): OnScrollListener {
return object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
try {
val lastVisibleItemPosition = (recyclerView.layoutManager as LinearLayoutManager).findLastCompletelyVisibleItemPosition()
recyclerView.adapter?.let {
val itemTotalCount = it.itemCount - 1
if (lastVisibleItemPosition == itemTotalCount) {
detectListenerRecyclerView.scrollDetectLastItem()
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
RecyclerView에는 OnScrollListener라는 인터페이스가 제공하는데 onScrolled와 onScrollStateChanged를 오버라이드 할 수 있다.
- onScrolled : 스크롤 감지
- onScrollStateChanged : 스크롤 상태 변환 감지
페이지네이션에서 필요한 함수는 onScrolled이고 해당 함수는 스크롤 중인 RecyclerView, x축, y축 3가지의 매개변수를 가진다. x축 같은 경우에는 스크롤 방향이 Horizontal일 때 사용하고 y축일 경우에는 Vertical 일 때 사용한다.
두 개의 변수를 가지고 값을 비교를 해야 하는데 하나는 findLastCompletelyVisibleItemPosition()에서 하단 마지막 아이템 포지션(lastVisibleItemPosition)이고 또 다른 하나는 화면에 보이고 있는 총아이템의 개수( itemTotalCount)이다. 두 변수의 값이 같을 때 스크롤 포지션이 하단에 도달할 때이므로 값이 같을 때 콘텐츠를 추가 호출한다.
- 추가 호출 리스너 인터페이스
페이지네이션 로직을 재사용하기 위해 리스너를 만들었다.
interface RecyclerViewScrollDetectListener {
fun scrollDetectLastItem()
}
- 추가 호출 api 호출
override fun scrollDetectLastItem() {
if (viewModel.totalPageCount > 0 && (viewModel.currentPageCount < viewModel.totalPageCount)) {
viewModel.categoryId?.let {
showLoading()
viewModel.giftPriceRangeMore()
} ?: run {
hideLoading()
showToast(R.string.call_merge)
}
}
}
추가 호출 Callback을 받았을 때 현재 페이지보다 총페이지가 작을 경우에 추가 호출을 진행하고 현재 페이지가 총 페이지 수보다 크거나 같을 경우에는 모든 페이지를 호출하였으므로 호출하지 않는다. 추가 호출했을 때 Api Response가 성공일 때 현재 페이지에 1을 더한다.
- 추가 호출 콘텐츠 리스트에 추가
viewModel.giftAddListModel.observe(viewLifecycleOwner) {
giftPriceRangeGiftListAdapter?.addData(it) //추가 호출한 가격대별 선물리스트 추가
}
'Android' 카테고리의 다른 글
안드로이드 4대 컴포넌트 (0) | 2021.12.27 |
---|---|
BottomSheetDialogFragment에서 Dagger 사용하기 (0) | 2021.12.06 |
디자인 아키텍처 3 - MVC (0) | 2021.11.16 |
Layout xml 그룹 관리 (0) | 2021.11.16 |
디자인 아키텍처 2 - MVP (0) | 2021.11.16 |