Is there a callback for when RecyclerView has finished showing its items after I've set it with an adapter?

前端 未结 3 1334
心在旅途
心在旅途 2020-12-02 12:56

Background

I\'ve made a library that shows a fast-scroller for RecyclerView (here, in case anyone wants), and I want to decide when to show and when to hide the fa

相关标签:
3条回答
  • 2020-12-02 13:25

    I've found a way to solve this (thanks to user pskink), by using the callback of LayoutManager :

    final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false) {
                @Override
                public void onLayoutChildren(final Recycler recycler, final State state) {
                    super.onLayoutChildren(recycler, state);
                    //TODO if the items are filtered, considered hiding the fast scroller here
                    final int firstVisibleItemPosition = findFirstVisibleItemPosition();
                    if (firstVisibleItemPosition != 0) {
                        // this avoids trying to handle un-needed calls
                        if (firstVisibleItemPosition == -1)
                            //not initialized, or no items shown, so hide fast-scroller
                            mFastScroller.setVisibility(View.GONE);
                        return;
                    }
                    final int lastVisibleItemPosition = findLastVisibleItemPosition();
                    int itemsShown = lastVisibleItemPosition - firstVisibleItemPosition + 1;
                    //if all items are shown, hide the fast-scroller
                    mFastScroller.setVisibility(mAdapter.getItemCount() > itemsShown ? View.VISIBLE : View.GONE);
                }
            };
    

    The good thing here is that it works well and will handle even keyboard being shown/hidden.

    The bad thing is that it gets called on cases that aren't interesting (meaning it has false positives), but it's not as often as scrolling events, so it's good enough for me.


    EDIT: there is a better callback that was added later, which doesn't get called multiple times. Here's the new code instead of what I wrote above:

            recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false) {
                @Override
                public void onLayoutCompleted(final State state) {
                    super.onLayoutCompleted(state);
                    final int firstVisibleItemPosition = findFirstVisibleItemPosition();
                    final int lastVisibleItemPosition = findLastVisibleItemPosition();
                    int itemsShown = lastVisibleItemPosition - firstVisibleItemPosition + 1;
                    //if all items are shown, hide the fast-scroller
                    fastScroller.setVisibility(adapter.getItemCount() > itemsShown ? View.VISIBLE : View.GONE);
                }
            });
    
    0 讨论(0)
  • 2020-12-02 13:30

    Leaving this here as an alternate approach. Might be useful in some cases. You can also make use of the LinearLayoutManagers onScrollStateChanged() and check when the scroll is idle.

    One thing to remember, when you load your view for the 1st time, this will not be called, only when the user starts scrolling and the scroll completes, will this be triggered.

    LinearLayoutManager layoutManager = new LinearLayoutManager(getContext(),
                    RecyclerView.HORIZONTAL, false) {
    
                @Override
                public void onScrollStateChanged(int state) {
                    super.onScrollStateChanged(state);
    
                    if (state == RecyclerView.SCROLL_STATE_IDLE) {
                            // your logic goes here
                        }
                    }
                }
            };
    
    0 讨论(0)
  • 2020-12-02 13:46

    I'm using the 'addOnGlobalLayoutListener' for this. Here is my example:

    Definition of an interface to perform the action required after the load:

    public interface RecyclerViewReadyCallback {
      void onLayoutReady();
    }
    

    on the RecyclerView, I trigger the onLayoutReady method when the load is ready:

    mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
      if (recyclerViewReadyCallback != null) {
        recyclerViewReadyCallback.onLayoutReady();
      }
      recyclerViewReadyCallback = null;
    });
    

    Note: The set to null is necessary to prevent the method from being called multiple times.

    0 讨论(0)
提交回复
热议问题