-
[Android] 무한스크롤 Infinite ScrollAOS 2023. 5. 17. 02:26반응형
무한스크롤이란?
API 데이터가 처음부터 모드 로드되지 않고, 사용자가 요청했을 때 다음 데이터가 로드되는 방법으로는 무한스크롤과 pagination(페이지 매기기)가 있습니다.
그 중 무한스크롤은 사용자가 스크롤 하면서 페이지의 하단에 도달했을 때, 다음 데이터가 로드되는 되는 UX 입니다.
pagination은 페이지를 분할하여 사용자가 페이지를 클릭해야 다음 데이터가 로드됩니다.
스크롤은 클릭보다 상호작용 비용이 낮아 더 나은 UX를 제공합니다.
무한스크롤을 구현해보기
1. 데이터 불러오기 (ViewModel)
class PlantListViewModel(private val repository: PlantRepository) : ViewModel() { private val _plantList = MutableLiveData<PlantList>() var plantList : LiveData<PlantList> = _plantList // 처음 list를 불러옵니다. fun initList() { repository.list { plantList -> _plantList.postValue(plantList) } } // 다음 list를 불러옵니다. fun nextList() { val currentPlantList = plantList.value ?: return repository.next(currentPlantList) { palntList -> // 기존 list와 다음 list를 더해줍니다. val mergedPlants = currenPlantList.plants.toMutableList() .apply { addAll(plantList.plants) } plantList.plants = mergedPlants _plantList.postValue(plantList) } } }
Next List를 불러올 때는 기존의 list와 합쳐서 다시 저장합니다.
2. 스크롤 감지
binding.plantList.addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) // 다음페이지 존재 여부 확인 if(viewModel.hasNextPage() == false) return; // 아직 로딩중인지 확인 if (viewModel.progressVisible.value != true) { // 스크롤이 끝에 도달했는지 확인 if (!binding.plantList.canScrollVertically(1)) { binding.progressBar.isVisible = true viewModel.nextList() } } } })
스크롤이 끝에 도달했으면 viewModel.next()를 호출하여 다음 list 데이터를 불러옵니다.
주의해야할 점은
- 다음 페이지가 없으면 (viewModel 에서 hasNextPage 활용)
- 아직 로딩중이라면 (progressBar 활용)
요청되지 않아야 합니다.
+) 다른 방법 : 마지막으로 보여진 아이템 position 이 전체 아이템 개수보다 5개 모자란 경우 데이터를 불러오자.
binding.plantList.addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) // 다음페이지 존재 여부 확인 if(viewModel.hasNextPage() == false) return; val layoutManager = binding.plantList.layoutManager val lastVisibleItem = (layoutManager as LinearLayoutManager) .findLastCompletelyVisibleItemPosition() // 아직 로딩중인지 확인 if (viewModel.progressVisible.value != true) { // 마지막으로 보여진 아이템 position 이 전체 아이템 개수보다 5개 모자란 경우 if (layoutManager.itemCount <= lastVisibleItem + 5) { binding.progressBar.isVisible = true viewModel.nextList() } } } })
마지막으로 보여진 아이템의 position을 이용하여
전체 아이템의 갯수보다 5개 부족한경우 데이터를 load 합니다.
3. list 감지 > adapter 업데이트
viewModel.plantList.observe(this){ binding.pullToRefresh.isRefreshing = false binding.progressBar.isVisible = false adapter.updatePlants(it.plants) } binding.pullToRefresh.setOnRefreshListener { viewModel.initList() } viewModel.initList()
- 처음 화면에 들어왔을 때 ( viewModel.initList() )
- pull to refresh를 했을 때 ( viewModel.initList() )
- 스크롤을 하단으로 내릴 때 ( viewModel.nextList() )
위의 세가지 경우에 list가 업데이트 됩니다.
4. PlantsAdapter.kt 의 update 함수
private val plants = mutableListOf<Plant>() fun updatePlants(plants: List<Plant>) { this.plants.clear() this.plants.addAll(plants) notifyDataSetChanged() }
adapter에서 list를 update 해주는 함수입니다.
반응형'AOS' 카테고리의 다른 글
[Android] LiveData에서 StateFlow 이전한 이유 (LiveData VS StateFlow) (1) 2023.07.05 [Andorid] local.properties를 이용하여 API URL, KEY 안전하게 숨기기 (0) 2023.06.13 [Android] 이미지 라이브러리(glide)없이 URL로 이미지 나타내기 (0) 2023.05.12 [Android] LiveData 와 Observer Pattern (0) 2023.03.20 [Android] 안드로이드 모듈화 Modularization 적용하기 (0) 2023.03.04