[Android] RecyclerView 의 최상단과 최하단 스크롤 이벤트 감지하기

유덕현
3 min readNov 10, 2017

--

RecyclerView 를 사용하다 보면 가끔 최상단과 최하단의 이벤트 감지가 필요하다(특히 채팅방에서의 예전채팅을 가져온다거나 포스팅의 다음 포스팅 로딩 처럼 페이징 로딩 처리시에 필요하다)

예전 ListView 시절부터 이런 문제는 보통(구글링하면 첫페이지에 나오는 자료들)

int visibleItemCount = layoutManager.getChildCount();
int totalItemCount = layoutManager.getItemCount();
int pastVisibleItems = layoutManager.findFirstCompletelyVisibleItemPosition();

if(pastVisibleItems+visibleItemCount >= totalItemCount){
// End of the list is here.
Log.i(TAG, "End of list");
}

이런식으로 현재 첫 번째로 표시되는 아이템의 인덱스와 표시외어 있는 아이템의 갯수를 더해 총 아이템의 갯수와 같으면 리스트의 최하단으로 판단한다.

코드가 직관적이지 않고 간결하지 않는 문제를 제외하고도 이 방법에는 치명적인 문제가 하나 있다. 실제로 리스트의 끝이 아니라 마지막 아이템이 보이기 시작하면서 부터 이 이벤트는 동작을 하게 된다. 이 문제는 특히 아이템 뷰의 높이가 높거나 천천히 스크롤 될시 의도치 않은 상황(완전한 처음과 끝이 아닌)이 만들어 질 위험이 있다.

그럼 완전한 RecyclerView의 끝을 알수 있는 방법은 없을까?

canScrollVertically(int direction) 이란 함수를 사용하면 가능하다.

이 함수는 말그대로 세로로(canScrollHorizontally로 가로 이벤트도 받을 수 있다) 스크롤이 가능한 상태임을 boolean 값으로 리턴해준다. 즉 리턴 값이 false면 해당 방향의 끝이라는 것이다.

인자값인 direction 은 Vertically 기준으로 -1이 위쪽, 1이 아래쪽이다.(별도의 final 값으로 정의된것이 없나 찾아봤지만 찾을 수 없었다. 다른 예제 에도 1과 -1로 코딩이 되어 있었다.) 즉

if(!myList.canScrollVertically(-1)) {
// 최상단
}
if(!myList.canScrollVertically(1)) {
// 최하단
}

으로 판단할 수 있는것이다. 이를 이용하여 setOnScrollListener 를 등록하여 아래처럼 사용할 수 있다.

myList.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (!myList.canScrollVertically(-1)) {
Log.i(TAG, "Top of list");
} else if (!myList.canScrollVertically(1)) {
Log.i(TAG, "End of list");
} else {
Log.i(TAG, "idle");
}
}
});

코드도 훨씬 간결하고 메서드의 이름도 직관적이다.

--

--