RecyclerView / LinearLayoutManager가 상단 또는 하단으로 스크롤되는지 확인하는 방법은 무엇입니까?


81

현재 다음 코드를 사용하여 SwipeRefreshLayout을 활성화해야하는지 확인하고 있습니다.

private void laySwipeToggle() {
    if (mRecyclerView.getChildCount() == 0 || mRecyclerView.getChildAt(0).getTop() == 0) {
        mLaySwipe.setEnabled(true);
    } else {
        mLaySwipe.setEnabled(false);
    }
}

그러나 여기에 문제가 있습니다. 다른 항목의보기 경계로 스크롤하면 mRecyclerView.getChildAt(0).getTop()0을 반환합니다.

문제

RecyclerView.isScrolledToBottom()또는 같은 것이 RecyclerView.isScrolledToTop()있습니까?

편집 : (mRecyclerView.getChildAt(0).getTop() == 0 && linearLayoutManager.findFirstVisibleItemPosition() == 0)종류의 RecyclerView.isScrolledToTop()이지만 RecyclerView.isScrolledToBottom()어떨까요?


후자는 마지막 자식에 대해 recyclerview의 맨 아래를 확인하여 얻을 수 있다고 가정합니다. 즉, mRecyclerView.getBottom () == linearLayoutmanager.findViewbyPosition (adapter.getItemCount ()-1) .getBottom ()
humblerookie

Arterius @Saren 당신은 한 번 봐 걸릴 수도 있습니다
Sheraz 아마드 Khilji에

답변:


109

해결책은 레이아웃 관리자에 있습니다.

LinearLayoutManager layoutManager = new LinearLayoutManager(this);

// Add this to your Recycler view
recyclerView.setLayoutManager(layoutManager);

// To check if at the top of recycler view
if(layoutManager.firstCompletelyVisibleItemPosition()==0){
    // Its at top
}

// To check if at the bottom of recycler view
if(layoutManager.lastCompletelyVisibleItemPosition()==data.size()-1){
    // Its at bottom
}

편집하다

항목 크기가 화면보다 큰 경우 다음을 사용하여 상위 이벤트를 감지하십시오.

RecyclerView recyclerView = (RecyclerView) view;
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();

int pos = linearLayoutManager.findFirstVisibleItemPosition();

if(linearLayoutManager.findViewByPosition(pos).getTop()==0 && pos==0){
    return true;
}

추신 : 사실, 당신이 RecyclerView직접 내부에 배치하면 SwipeRefreshview이것을 할 필요가 없습니다


아니요, RecyclerView가 SwipeRefreshLayout의 직계 자식 인 경우에도 여전히 발생합니다. 그러나 firstCompletelyVisibleItemPosition을 확인하면 문제가 해결됩니다. 여기서 뭔가를 가리켜 야합니다. 완전히 보이는 항목이 없으면 firstCompletelyVisibleItemPosition ()은 -1을 반환합니다. 따라서 첫 번째 항목이 위로 스크롤 될 때 RecyclerView에 맞지 않으면이 솔루션이 작동하지 않습니다. 그러나 이것은 매우 드문 상황입니다.
eluleci

1
@eluleci : 목록이 상단에 있는지 확인 RecyclerView rc = (RecyclerView) view; LinearLayoutManager lm = (LinearLayoutManager) rc.getLayoutManager (); if (lm.findViewByPosition (lm.findFirstVisibleItemPosition ()). getTop () == 0 && lm.findFirstVisibleItemPosition () == 0) return true; // 아이템이 화면보다 큰 경우
evn 작동합니다

2
항목 (첫 번째 또는 마지막)이 전체 화면보다 크면 실패합니다. first/lastCompletelyVisibleItemPosition()는 -1을 반환 하기 때문에 완전히 보이는 항목이 전혀 없음을 의미합니다.
Subin Sebastian

4
모두 lastVisibleItemPositionlastCompletelyVisibleItemPosition일을하지 않습니다. (방법을 해결할 수 없음). 도움?
Stardust

4
findLastCompletelyVisibleItemPosition마지막 항목의 높이가 화면 높이보다 크면 실패합니다. 이는 마지막 항목이 표시되지만 완전히 표시되지는 않음을 의미하므로 layout.findLastCompletelyVisibleItemPosition()=-1(RecyclerView.NO_POSITION). lastVisibleItemPosition레이아웃의 마지막보기 하단을 사용 하고 확인하는 것이 더 안전합니다.
사라짐

78

recyclerView.canScrollVertically(int direction)스크롤이 가능한지 여부 만 알고 싶다면를 시도해 볼 수 있습니다 .

방향 정수 :

  • -1 최대
  • 아래로 1
  • 0은 항상 거짓을 반환합니다.

그래도이 작업은 간격을두고 반복되어야합니다. 그렇죠?
Stardust

1
당신은 recyclerView.addOnScrollListener..it에서이 ... 마법처럼 덕분에 작동 할 수 있습니다에서
therealprashant

2
큰! 스크롤이 끝날 때 false를 반환합니다.이 이벤트가 필요했습니다.
box

1
우수한. onScrollStateChanged나를 위해 이것을 사용하십시오 .
Lym Zoy

5
방향 정수 : 업은 -1, 다운은 1, 0은 항상 거짓을 반환합니다.
Grux

33

RecyclerView아래로 스크롤 되는지 확인하기 위해 . 다음 코드를 사용하십시오.

/**
     * Check whether the last item in RecyclerView is being displayed or not
     *
     * @param recyclerView which you would like to check
     * @return true if last position was Visible and false Otherwise
     */
    private boolean isLastItemDisplaying(RecyclerView recyclerView) {
        if (recyclerView.getAdapter().getItemCount() != 0) {
            int lastVisibleItemPosition = ((LinearLayoutManager) recyclerView.getLayoutManager()).findLastCompletelyVisibleItemPosition();
            if (lastVisibleItemPosition != RecyclerView.NO_POSITION && lastVisibleItemPosition == recyclerView.getAdapter().getItemCount() - 1)
                return true;
        }
        return false;
    }

추가 정보

구현하려는 경우 ScrollToBottomRecyclerViewEdittext입니다 tapped그럼 내가 추가하는 것이 좋습니다 일초 지연을 다음과 같이 :

 edittext.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_UP)
                    if (isLastItemDisplaying(recyclerView)) {
// The scrolling can happen instantly before keyboard even opens up so to handle that we add 1 second delay to scrolling
                        recyclerView.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                recyclerView.smoothScrollToPosition(recyclerView.getAdapter().getItemCount() - 1);

                            }
                        }, 1000);
                    }
                return false;
            }
        });

나를 위해 일했습니다. 나는 RecyclerView의에 추가했다 addOnScrollListener () 하지만
aphoe

1
이것은 recyclerview에 하나의 항목이 있고 완전히 보이는 사소한 경우에는 작동하지 않습니다.
techtinkerer

당신은 하루에 저장
리나

22

@Saren Arterius , RecycleViewaddOnScrollListener를 사용하면 아래와 같이 Vertical RecycleView의 스크롤되는 상단 또는 하단을 찾을 수 있습니다.

RecyclerView rv = (RecyclerView)findViewById(R.id.rv);

rv.addOnScrollListener(new RecyclerView.OnScrollListener() {

            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

                if (dy < 0) {
                    // Recycle view scrolling up...

                } else if (dy > 0) {
                    // Recycle view scrolling down...
                }
            }
        });

6

recyclerView.canScrollVertically (int direction) 을 사용 하여 스크롤의 상단 또는 하단에 도달했는지 확인하십시오.

아래로 스크롤하는 경우 방향 = 1 (하단)

방향 = -1 (위로 스크롤)

메서드가 false를 반환하면 방향에 따라 상단 또는 하단에 도달했음을 의미합니다.


많은 감사합니다!
Ferer Atlus 20.06.17

5

layoutManager에 대한 참조를 유지하고 다음과 같이 리사이클 러 뷰에서 onScrollListener를 설정하십시오.

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);

        visibleItemCount = mRecyclerView.getChildCount();
        totalItemCount = mLayoutManager.getItemCount();
        firstVisibleItemIndex = mLayoutManager.findFirstVisibleItemPosition();

        //synchronizew loading state when item count changes
        if (loading) {
            if (totalItemCount > previousTotal) {
                loading = false;
                previousTotal = totalItemCount;
            }
        }
        if (!loading)
            if ((totalItemCount - visibleItemCount) <= firstVisibleItemIndex) {
                // Loading NOT in progress and end of list has been reached
                // also triggered if not enough items to fill the screen
                // if you start loading
                loading = true;
            } else if (firstVisibleItemIndex == 0){
                // top of list reached
                // if you start loading
                loading = true;
            }
        }
    }
});

1
setOnScrollListner현재 사용되지 않습니다.
Shajeel Afzal 2015 년

2
당신은 사용해야 addOnScrollListener@shajeelAfzal 말했듯이 있기 때문에 setOnScrollListener지금은 사용되지 않습니다, 당신은 사용해야 addOnScrollListener@shajeelAfzal 말했듯이 있기 때문에 setOnScrollListener지금은 사용되지 않습니다 확인 여기
Vasilisfoo

무엇입니까 previousTotal?
CoolMind

3

다음을 사용하여 상단을 감지 할 수 있습니다.

 recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
          }

        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            if(IsRecyclerViewAtTop())
            {
                //your recycler view reached Top do some thing
             }
        }
    });

  private boolean IsRecyclerViewAtTop()   {
        if(recyclerView.getChildCount() == 0)
            return true;
        return recyclerView.getChildAt(0).getTop() == 0;
    }

당신이 도달 위에 한 번 손가락을 놓을 때 reacyclerview 최고 체크에 도달하는 즉시 당신이 감지하려는 경우, 상단을 감지 if(IsRecyclerViewAtTop())내부 onScrolled 방법을


3
이것은 잘못된 것 같습니다. getChildAt()의 첫 번째 자식을 반환하며 ViewGroup, 이는 목록의 첫 번째 요소와 다를 수 있습니다. 해당 자식이 recyclerview의 상단과 완벽하게 정렬되면 상단에 IsRecyclerViewAtTop()있지 않더라도 메서드가 true를 반환합니다.
aspyct

2

recyclerview가 맨 위 또는 맨 아래에 있음을 알기 위해 RecyclerViewHelper를 작성했습니다.

public class RecyclerViewHelper {
public static boolean isAtTop(RecyclerView recyclerView) {
    if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
        return isAtTopBeforeIceCream(recyclerView);
    } else {
        return !ViewCompat.canScrollVertically(recyclerView, -1);
    }
}

private static boolean isAtTopBeforeIceCream(RecyclerView recyclerView) {
    RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
    if (layoutManager instanceof LinearLayoutManager) {
        LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;
        int pos = linearLayoutManager.findFirstVisibleItemPosition();
        if (linearLayoutManager.findViewByPosition(pos).getTop() == recyclerView.getPaddingTop() && pos == 0)
            return true;
    }
    return false;
}


public static boolean isAtBottom(RecyclerView recyclerView) {
    if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
        return isAtBottomBeforeIceCream(recyclerView);
    } else {
        return !ViewCompat.canScrollVertically(recyclerView, 1);
    }
}

private static boolean isAtBottomBeforeIceCream(RecyclerView recyclerView) {
    RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
    int count = recyclerView.getAdapter().getItemCount();
    if (layoutManager instanceof LinearLayoutManager) {
        LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;
        int pos = linearLayoutManager.findLastVisibleItemPosition();
        int lastChildBottom = linearLayoutManager.findViewByPosition(pos).getBottom();
        if (lastChildBottom == recyclerView.getHeight() - recyclerView.getPaddingBottom() && pos == count - 1)
            return true;
    }
    return false;
}

}


2

당신은 이것을 할 수 있습니다 그것은 나를 위해 일합니다

      mRecycleView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            }
        }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                int topRowVerticalPosition = (recyclerView == null || recyclerView.getChildCount() == 0) ?
                        0 : recyclerView.getChildAt(0).getTop();
                LinearLayoutManager linearLayoutManager1 = (LinearLayoutManager) recyclerView.getLayoutManager();
                int firstVisibleItem = linearLayoutManager1.findFirstVisibleItemPosition();
                swipeRefreshLayout.setEnabled(firstVisibleItem == 0 && topRowVerticalPosition >= 0);
            }
        });

2

RecyclerView가 아래로 스크롤되었는지 확인하려면 스크롤바에 사용 된 메서드를 재사용 할 수 있습니다.

편의상 Kotlin 확장 함수로 작성된 계산입니다.

fun RecyclerView.isScrolledToBottom(): Boolean {
    val contentHeight = height - (paddingTop + paddingBottom)
    return computeVerticalScrollRange() == computeVerticalScrollOffset() + contentHeight
}

좋은 해결책! 스크롤 크기가 1 off 인 문제를 보았습니다. 아래쪽에서 스크롤했지만 (아마 반올림 문제 일 수 있음) 여백을 사용하도록 코드를 변경했습니다.fun RecyclerView.isScrolledToBottom(margin: Int = 1): Boolean { val contentHeight = height - (paddingTop + paddingBottom) return computeVerticalScrollRange() - computeVerticalScrollOffset() - contentHeight >= margin }
Renso Lohuis

마진보다 작거나 같습니다. 다음과 같이 :fun RecyclerView.isScrolledToBottom(margin: Int = 1): Boolean { val contentHeight = height - (paddingTop + paddingBottom) return computeVerticalScrollRange() - computeVerticalScrollOffset() - contentHeight <= margin }
Renso Lohuis

1

OnTouchListener로 시도 할 수 있습니다.

recyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        if (e.getAction() == MotionEvent.ACTION_UP
            || e.getAction() == MotionEvent.ACTION_MOVE){
        if (mLinearLayoutManager.findFirstCompletelyVisibleItemPosition() > 0)
        {
        // beginning of the recycler 
        }

        if (mLinearLayoutManager.findLastCompletelyVisibleItemPosition()+1 < recyclerView.getAdapter().getItemCount())
        {
        // end of the recycler 
        }         
     }             
return false;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.