RecyclerView and SwipeRefreshLayout

后端 未结 12 1841
再見小時候
再見小時候 2020-12-22 15:46

I\'m using the new RecyclerView-Layout in a SwipeRefreshLayout and experienced a strange behaviour. When scrolling the list back to the top sometim

相关标签:
12条回答
  • 2020-12-22 16:03

    This is how I have resolved this issue in my case. It might be useful for someone else who end up here for searching solutions similar to this.

    recyclerView.addOnScrollListener(new OnScrollListener()
        {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy)
            {
                // TODO Auto-generated method stub
                super.onScrolled(recyclerView, dx, dy);
            }
    
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState)
            {
                // TODO Auto-generated method stub
                //super.onScrollStateChanged(recyclerView, newState);
                int firstPos=linearLayoutManager.findFirstCompletelyVisibleItemPosition();
                if (firstPos>0)
                {
                    swipeLayout.setEnabled(false);
                }
                else {
                    swipeLayout.setEnabled(true);
                }
            }
        });
    

    I hope this might definitely help someone who are looking for similar solution.

    0 讨论(0)
  • 2020-12-22 16:06

    The krunal's solution is good, but it works like hotfix and does not cover some specific cases, for example this one:

    Let's say that the RecyclerView contains an EditText at the middle of screen. We start application (topRowVerticalPosition = 0), taps on the EditText. As result, software keyboard shows up, size of the RecyclerView is decreased, it is automatically scrolled by system to keep the EditText visible and topRowVerticalPosition should not be 0, but onScrolled is not called and topRowVerticalPosition is not recalculated.

    Therefore, I suggest this solution:

    public class SupportSwipeRefreshLayout extends SwipeRefreshLayout {
        private RecyclerView mInternalRecyclerView = null;
    
        public SupportSwipeRefreshLayout(Context context) {
            super(context);
        }
    
        public SupportSwipeRefreshLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public void setInternalRecyclerView(RecyclerView internalRecyclerView) {
            mInternalRecyclerView = internalRecyclerView;
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            if (mInternalRecyclerView.canScrollVertically(-1)) {
                return false;
            }
            return super.onInterceptTouchEvent(ev);
        }
    }
    

    After you specify internal RecyclerView to SupportSwipeRefreshLayout, it will automatically send touch event to SupportSwipeRefreshLayout if RecyclerView cannot be scrolled up and to RecyclerView otherwise.

    0 讨论(0)
  • 2020-12-22 16:08

    In case of someone find this question and is not satisfied by the answer :

    It seems that SwipeRefreshLayout is not compatible with adapters that have more than 1 item type.

    0 讨论(0)
  • 2020-12-22 16:11

    Source Code https://drive.google.com/open?id=0BzBKpZ4nzNzURkRGNVFtZXV1RWM

    recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
    
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        }
    
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            swipeRefresh.setEnabled(linearLayoutManager.findFirstCompletelyVisibleItemPosition() == 0);
        }
    });
    
    0 讨论(0)
  • 2020-12-22 16:12

    Here's one way to handle this, which also handles ListView/GridView.

    public class SwipeRefreshLayout extends android.support.v4.widget.SwipeRefreshLayout
      {
      public SwipeRefreshLayout(Context context)
        {
        super(context);
        }
    
      public SwipeRefreshLayout(Context context,AttributeSet attrs)
        {
        super(context,attrs);
        }
    
      @Override
      public boolean canChildScrollUp()
        {
        View target=getChildAt(0);
        if(target instanceof AbsListView)
          {
          final AbsListView absListView=(AbsListView)target;
          return absListView.getChildCount()>0
                  &&(absListView.getFirstVisiblePosition()>0||absListView.getChildAt(0)
                  .getTop()<absListView.getPaddingTop());
          }
        else
          return ViewCompat.canScrollVertically(target,-1);
        }
      }
    
    0 讨论(0)
  • 2020-12-22 16:13

    I came across the same problem recently. I tried the approach suggested by @Krunal_Patel, But It worked most of the times in my Nexus 4 and didn't work at all in samsung galaxy s2. While debugging, recyclerView.getChildAt(0).getTop() is always not correct for RecyclerView. So, After going through various methods, I figured that we can make use of the method findFirstCompletelyVisibleItemPosition() of the LayoutManager to predict whether the first item of the RecyclerView is visible or not, to enable SwipeRefreshLayout.Find the code below. Hope it helps someone trying to fix the same issue. Cheers.

        recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
    
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            }
    
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                swipeRefresh.setEnabled(linearLayoutManager.findFirstCompletelyVisibleItemPosition() == 0);
            }
        });
    
    0 讨论(0)
提交回复
热议问题