스크롤이 잘 되지 않아요!!

Vertical RecyclerView안에 Horizontal RecyclerView를 구현하는 경우 스크롤이 잘되지 않는 경우가 발생할 수 있습니다.

상위/하위 RecyclerView 상호간 터치이벤트 간섭으로 인해 원치 않는 동작이 발생기 때문인데요.

RecyclerView는 NestedScrollingChild 인터페이스의 구현으로 중첩된 스크롤(nested scroll)에 대한 내용을 지원하고 있습니다. RecyclerView가 초기화 되고 중첩스크롤에 대한 기능이 true로 되어있는데 이를 비활성화 해주면 문제가 해결됩니다. 

또한 CoordinatorLayout을 사용하면서 CollapsingToolbarLayout과 AppBarBehavior를 사용하는 경우의 스크롤 오동작도 마찬가지로 하위 RecyclerView의 setNestedScrollingEnabled(false); 를 호출하면 해결이 됩니다.


19.08.19 추가 
원문 : https://rubensousa.com/2019/08/16/nested_recyclerview_part1/

기본 RecyclerView 사용시 아래와 같은 스크롤 이슈가 발생합니다.

문제 1 영상

문제2 영상

 

수정하는 방법

두 영상에서 보이는 이슈를 모두 해결하기 위해서는 RecyclerView를 상속한 OrientationAwareRecyclerView를 만들고 onInterceptTouchEvent를 재정의 해야합니다.

사용자가 손가락을 움질일때의 스크롤 방향이 RecyclerView의 방향인지 확인해야하는데, 만약 방향이 일치한다면 터치이벤트를 가로채고 아니면 그대로 동작하게 내버려둡니다.

@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
   final LayoutManager lm = getLayoutManager();

   if (lm == null) {
       return super.onInterceptTouchEvent(e);
   }

   boolean allowScroll = true;

   switch (e.getActionMasked()) {
       case MotionEvent.ACTION_DOWN: {
           lastX = e.getX();
           lastY = e.getY();
           // If we were scrolling, stop now by faking a touch release
           if (scrolling) {
               MotionEvent newEvent = MotionEvent.obtain(e);
               newEvent.setAction(MotionEvent.ACTION_UP);
               return super.onInterceptTouchEvent(newEvent);
           }
           break;
       }
       case MotionEvent.ACTION_MOVE: {
           // We're moving, so check if we're trying
           // to scroll vertically or horizontally
           // so we don't intercept the wrong event.
           float currentX = e.getX();
           float currentY = e.getY();
           float dx = Math.abs(currentX - lastX);
           float dy = Math.abs(currentY - lastY);
           allowScroll = dy > dx ? lm.canScrollVertically() : lm.canScrollHorizontally();
           break;
       }
   }

   if (!allowScroll) {
       return false;
   }

   return super.onInterceptTouchEvent(e);
}

위의 코드를 적용하여 문제점을 해결한 영상을 아래에서 확인해보세요.

해결1 영상

해결2 영상

원문 출처의 샘플 Github:https://github.com/rubensousa/RecyclerViewNestedExample/

카테고리: 미분류

6개의 댓글

Czle · 2019년 7월 25일 10:42 오전

감사합니다! 고민하고있었는데 ㅠㅠ

wicked · 2019년 8월 19일 7:36 오후

혹시 nested scrollview(vertical) 안에 recyclevire(horizontal)으로 구성되어 있을 경우에는 어떻게 대응하는게 좋을까요?

wicked · 2019년 8월 19일 7:37 오후

nestedscroll(vertical)안에 recyclerview(horizontal)으로 구성되었을 경우에는 어떻게 대응하는게 좋을까요?

wicked · 2019년 8월 19일 7:38 오후

nestedscrollview(vertical)안에 recyclerview(horizontal)으로 구성되었을 경우 어떻게 해야할까요?

    Charlezz · 2019년 8월 19일 9:58 오후

    부모뷰가 RecyclerView일 때랑 동일 합니다.

j · 2021년 10월 5일 2:52 오후

저도 위 댓글과 같은 이슈인데, 동일하다는건 예를 들어 OrientationAwareScrollView 를 위에 OrientationAwareRecyclerView 처럼 만들고
사용하면 된다는것인가요??
서로 상속한 뷰가 달라서 어떻게 해야 할 지 감이 안오네요 ㅠ

답글 남기기

Avatar placeholder

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.