안드로이드에서 무한 스크롤 사용하기

이형진·2021년 6월 7일
0

안드로이드

목록 보기
1/3
post-thumbnail

Infinite Scroll (무한 스크롤)

한번에 모든 게시글을 불러오는 행위는 로딩 시간이 길어지는 등 사용자에게 좋지 않은 경험을 제공합니다.

서버에서 가져오는 데이터를 나누기 위해서는 페이지를 만드는 방법(페이지네이션)도 있지만,

모바일의 경우 페이지네이션 방식보다 무한 스크롤을 구현하는 것이 사용자가 더 좋은 경험을 할 수 있게 합니다.

무한 스크롤은

  1. 서버 측에서 분리된 데이터를 받는다
  2. 사용자의 RecyclerView 스크롤의 위치를 확인한다.
  3. 스크롤의 위치가 끝에 도달(RecyclerView의 마지막 item이 보임)하면 더 많은 데이터를 가져온다.

의 과정을 통해 구현됩니다.

사용방법

recyclerview.addOnScrollListener

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와 ViewType

무한 스크롤 뿐 아니라 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를 시켜주면 됩니다.

0개의 댓글