Android/RecyclerView

[Android] RecyclerView에서 페이징 처리하기 #1

O_Gyong 2022. 12. 16.

RecyclerView에서 리스트를 스크롤하다가 어느 순간에 로딩 화면이 뜨면서 리스트가 늘어나는 것을 본 적 있을 것이다.

Adapter에서 등록된 list가 마지막에 도달했을 때를 감지하여 로딩 화면을 띄우고 다음 페이지를 호출하는 것이다.

 

RecyclerView는 스크롤 상태와 리스트의 포지션에 대한 정보를 알려주는 addOnScrollListener 메서드를 제공한다.

addOnScrollListener를 이용해서 페이징 처리를 해보려고 한다.


RecyclerView 페이징 예제

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="first_page">
        <item>1번</item>
        <item>2번</item>
        <item>3번</item>
        <item>4번</item>
        <item>5번</item>
        <item>6번</item>
        <item>7번</item>
        <item>8번</item>
        <item>9번</item>
        <item>10번</item>
    </string-array>

    <string-array name="second_page">
        <item>11번</item>
        <item>12번</item>
        <item>13번</item>
        <item>14번</item>
        <item>15번</item>
        <item>16번</item>
        <item>17번</item>
        <item>18번</item>
        <item>19번</item>
        <item>20번</item>
    </string-array>

    <string-array name="third_page">
        <item>21번</item>
        <item>22번</item>
        <item>23번</item>
        <item>24번</item>
        <item>25번</item>
        <item>26번</item>
        <item>27번</item>
        <item>28번</item>
        <item>29번</item>
        <item>30번</item>
    </string-array>
</resources>

총 3페이지가 있다고 가정하여 res>values에 array를 만들어줬다.

원래는 page 정보를 서버에 넘겨주면 되겠지만, 임시방편으로..


val sampleList = resources.getStringArray(R.array.first_page).toList() as ArrayList<String>
mAdapter.setList(sampleList)

어댑터에 첫 번째 페이지 정보를 넘겨서 초기 화면을 그려준다.

 

    mBinding.rvMain.addOnScrollListener(object: RecyclerView.OnScrollListener(){
        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
            super.onScrolled(recyclerView, dx, dy)

            // 리사이클러뷰 아이템 위치 찾기, 아이템 위치가 완전히 보일때 호출됨
            val rvPosition =
                (recyclerView.layoutManager as LinearLayoutManager?)!!.findLastCompletelyVisibleItemPosition()

            // 리사이클러뷰 아이템 총개수 (index 접근 이기 때문에 -1)
            val totalCount =
                recyclerView.adapter?.itemCount?.minus(1)

            // 페이징 처리
            if(rvPosition == totalCount) {
                page++
                if(page == 2) {
                    sampleList.addAll(resources.getStringArray(R.array.second_page).toList() as ArrayList<String>)
                    mAdapter.setList(resources.getStringArray(R.array.second_page).toList() as ArrayList<String>)
                }else if (page ==3) {
                    sampleList.addAll(resources.getStringArray(R.array.third_page).toList() as ArrayList<String>)
                    mAdapter.setList(resources.getStringArray(R.array.third_page).toList() as ArrayList<String>)
                }
            }
        }
    })
}

addOnScrollListener를 선언하고 onScrolled 콜백 메서드를 통해 스크롤될 때마다 RecyclerView의 정보를 구한다.

 

findLastCompletelyVisibleItemPosition은 스크롤을 할 때 마지막으로 보이는 아이템의 포지션을 반환한다.

RecyclerView의 총 개수와 마지막으로 보이는 아이템의 포지션이 같을 때가 리스트의 끝이라는 것을 알 수 있다.

이때 페이지 값을 늘려서 다음 페이지의 리스트 정보를 받아 어댑터에 리스트를 전달하면 된다.

필요에 따라 이 부분에서 ProgressBar를 추가하여 로딩 처리를 해주면 될 것 같다.

 

addOnScrollListener 참고 자료

onScrolled 참고 자료

findLastCompletelyVisibleItemPosition 참고 자료


fun setList(notifyList: ArrayList<String>) {
    mList.addAll(notifyList)
    notifyItemRangeChanged(0, mList.size)
}

참고로 어댑터에서는 받아온 리스트를 기존 리스트에 이어 붙이고 갱신만 해줬다.


[Android] RecyclerView에서 페이징 처리하기 #1 - RecyclerView 페이징 예제

전체 코드