한번에 모든 게시글을 불러오는 행위는 로딩 시간이 길어지는 등 사용자에게 좋지 않은 경험을 제공합니다.
서버에서 가져오는 데이터를 나누기 위해서는 페이지를 만드는 방법(페이지네이션)도 있지만,
모바일의 경우 페이지네이션 방식보다 무한 스크롤을 구현하는 것이 사용자가 더 좋은 경험을 할 수 있게 합니다.
무한 스크롤은
의 과정을 통해 구현됩니다.
onScrollListener안의 onScrolled 메서드는 recyclerview의 스크롤 변화를 감지합니다.
무한 스크롤을 구현할 때에는 onScrolled 메서드에서 스크롤의 움직임을 감지하여 리스트의 마지막에 도달했는지 확인합니다.
Activity
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
//리스트에서 마지막으로 보이는 position이 리스트의 마지막 인덱스와 같은지 검사합니다 (저의 경우에는 리스트에 기본값이 있어서 lastIndex -1을 하였습니다)
if (layoutManager != null &&
layoutManager.findLastCompletelyVisibleItemPosition() == boardIdxList.lastIndex - 1) {
if (MORE_LOADING && !LOADING) // 추가로 로딩할 게시판이 있는지, 현재 로딩 중인지를 체크하는 변수
{
LOADING = true // 현재 로딩 중, 게시글을 불러오면 false로 바꿔줍니다
rv_board.post {
boardAdapter.showProgressBar() // recyclerView에 ProgressBar를 띄우는 메서드, 게시글을 다 불러오면 progressbar를 지워줍니다.
loadBoard() //추가 데이터 로드
}
}
}
}
무한 스크롤 뿐 아니라 recyclerview에서 여러 Layout을 inflate하려면 ViewType에 따라 ViewHolder를 바꾸어주는 작업이 필요하다.
View에 맞는 ViewHolder를 만든 뒤 Adapter에서 getItemViewType을 override한다.
Adapter.getItemViewType
override fun getItemViewType(position: Int): Int {
val board = boardList[position]
if (null != board?.images) {
return 0
} else if (null != board) {
return 1
} else {
return -1
}
}
전달받은 데이터에 따라 ViewType을 설정합니다.
(저의 경우 이미지가 포함된 View라면 0, 이미지가 포함되지 않는 경우 1, 그 외 (progressbar)는 -1로 반환하였습니다.)
onCreateViewHolder
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
context = parent.context
when (viewType) {
0 -> {
return BoardViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.rv_board_item, parent, false)
)
}
1 -> {
return BoardViewHolderNoImages(
LayoutInflater.from(parent.context)
.inflate(R.layout.rv_board_item_no_image, parent, false)
)
}
else -> {
return LoadingViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.rv_item_loading, parent, false)
)
}
}
}
onCreateViewHolder에서 viewType에 대해 각자 다른 ViewHolder에게 return 해줍니다.
onBindViewHolder
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is BoardViewHolder) {
holder.bind(boardList[position]!!)
} else if (holder is BoardViewHolderNoImages) {
holder.bind(boardList[position]!!)
}
}
onBindViewHolder에서 holder에 따라 bind를 시켜주면 됩니다.