개발 공부/Android / / 2022. 10. 1. 17:12

[Android Kotlin] RecyclerView 데이터 변경 시 스크롤 위치 유지하기(onSaveInstanceState(),onRestoreInstanceState() )

페이징 구현시 RecyclerView가 바닥을 인지해서 데이터가 바뀔 때 마다 RecyclerView의 focus가 계속 최상단으로 이동해서 데이터가 바뀌어도 스크롤 위치가 바뀌지 않게 하기 위해서 진행 

1. 전역변수로 Parcelable 선언 및 초기화

private var recyclerViewState: Parcelable? = null

2. RecyclerView의 상태를 저장해야할 시점에 onSaveInstanceState() 호출

페이징이 시작되기 전의 상태를 저장할 필요가 있기 때문에 그 시점에 넣어주었다. 

recyclerViewState =binding.rcyMainMovieList.layoutManager.onSaveInstanceState() //RecyclerView 현 상태 저장

실 적용

//RecyclerView 바닥 인지
        binding.rcyMainMovieList.addOnScrollListener(
            object: RecyclerView.OnScrollListener() {
                override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                    if (!binding.rcyMainMovieList.canScrollVertically(1)) {//최하단 인지하면
                        val resultSize =  mainViewModel.liveSearchResult.value?.size //현재 보이는 영화 리스트 사이즈
                        val original = mainViewModel.movieSearchResult.size //전체 영화 리스트 사이트
                        if (resultSize != null) {
                            recyclerViewState =
                                binding.rcyMainMovieList.layoutManager?.onSaveInstanceState()!! //RecyclerView 현 상태 저장
                            if(original != resultSize){
                                binding.pbMainLoadItem.visibility = View.VISIBLE
                            }else{
                                binding.pbMainLoadItem.visibility = View.INVISIBLE
                            }
                            Handler(Looper.getMainLooper()).postDelayed({
                               // 현재 보이는 결과 사이즈가 원본보다 작을 때 영화 5개씩 불러오기
                                mainViewModel.getNextPage(resultSize)
                                binding.pbMainLoadItem.visibility = View.INVISIBLE
                            }, 1000)

                        }
                    }
                }
            }
        )

 

3.저장한 상태 불러서 적용하기

if(recyclerViewState != null)
binding.rcyMainMovieList.layoutManager.onRestoreInstanceState(recyclerViewState)//저장한 RecyclerView 상태 set

실 적용

        mainViewModel.liveSearchResult.observe(this) {
            //TODO:it은 즐겨찾기 데이터가 처리된 데이터로 나와야
            adapter = SearchResultAdapter(this, it)
            binding.rcyMainMovieList.adapter = adapter
            binding.rcyMainMovieList.layoutManager = layoutManager

            // RecyclerView의 데이터 값이 바뀌어도 item 위치 그대로 하기 위해 추가
            if(recyclerViewState != null)
            binding.rcyMainMovieList.layoutManager!!.onRestoreInstanceState(recyclerViewState)//저장한 RecyclerView 상태 set

        }
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유