Scroll up does not work with SwipeRefreshLayout in Listview

后端 未结 10 1402
失恋的感觉
失恋的感觉 2020-12-01 10:36

I want to implement scroll to refresh functionality with a listView. Also there are other view elements in the same layout file which are displayed if the list is empty. Her

相关标签:
10条回答
  • 2020-12-01 10:44

    I had a similar problem where the child of my SwipeRefreshLayout was a FrameLayout which had a TextView and ListView as children and when I scrolled up on the ListView it would try to do a refresh.

    I fixed it by using a custom FrameLayoutwhich overrides the canScrollVertically() method

    package com.wi.director.ui.common;

    import android.content.Context;
    import android.util.AttributeSet;
    import android.widget.FrameLayout;
    
    /**
     * Created by devansh on 9/22/15.
     */
    public class FrameLayoutForSwipeRefresh extends FrameLayout {
    
        public FrameLayoutForSwipeRefresh(Context context) {
            super(context);
        }
    
        public FrameLayoutForSwipeRefresh(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public FrameLayoutForSwipeRefresh(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        public boolean canScrollVertically(int direction) {
            if (super.canScrollVertically(direction)) {
                return true;
            }
    
            int cc = getChildCount();
            for (int i = 0; i < cc; i++) {
                if (getChildAt(i).canScrollVertically(direction)) {
                    return true;
                }
            }
    
            return false;
        }
    }
    
    0 讨论(0)
  • 2020-12-01 10:48

    Basically, we want to scroll something scrollable. We can put all views in ScrollView.

    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout 
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">
    
            </LinearLayout>
        </ScrollView>
    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
    

    But scrolling ListView may require some modifications - wrap_content ListView

    0 讨论(0)
  • 2020-12-01 10:50

    Make your own implementation of SwipeRefreshLayout and override the canChildScrollUp in this way:

    @Override
    public boolean canChildScrollUp() {
    if (scrollView != null)
        return scrollView.canScrollVertically(-1);
    
    return false;
    }
    

    just replace with any subclass of ScrollView.

    0 讨论(0)
  • 2020-12-01 10:50

    If RecyclerView or ListView is not the direct child of SwipeRefreshLayout then this issue occurs.

    Simplest solution is to provide OnChildScrollUpCallback implementation and return the results appropriately. In Kotlin code below, refreshLayout is SwipeRefreshLayout and recyclerView is RecyclerView as can be seen in xml layout code as well.

    refreshLayout.setOnChildScrollUpCallback(object : SwipeRefreshLayout.OnChildScrollUpCallback {
      override fun canChildScrollUp(parent: SwipeRefreshLayout, child: View?): Boolean {
        if (recyclerView != null) {
          return recyclerView.canScrollVertically(-1)
        }
        return false
      }
    })
    

    While xml layout is something like this,

     <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
        android:id="@+id/swipeRefresh"
        ...
        lots of other views i.e TextView, ImageView, MotionLayout
        ...
        ...
        ...
        <androidx.recyclerview.widget.RecyclerView
           android:id="@+id/recyclerView".../>
           
        ...
        ...
        ...
    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
    
    0 讨论(0)
  • 2020-12-01 10:56

    In order for SwipeRefreshLayout to work, it needs to be the direct parent of your ListView, and the ListView should be the first active child view of the SwipeRefreshLayout.

    The documentation for SwipeRefreshLayout says that the ListView should be the only child, but it is okay if it has more than one child as long as the ListView is first. This means, for instance, that SwipeRefreshLayout will work fine if you are using an adapter with a view for "empty". For example:

    <android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/swipe_refresh"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".NearbyJobsActivity$PlaceholderFragment">
    
        <ListView
            android:id="@android:id/list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:divider="@color/list_divider"
            android:dividerHeight="1dp"
            android:listSelector="@drawable/list_row_selector" />
    
        <TextView
            android:id="@android:id/empty"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center" />
    
    </android.support.v4.widget.SwipeRefreshLayout>
    

    If you can manage this sort of layout, then SwipeRefreshLayout will work fine and you won't need any of the workarounds listed in other answers.

    My own problem was that that I was loading my ListView as a Fragment, so I actually had:

    <SwipeRefreshLayout>
    
        <FrameLayout>           )
             <ListView/>        \ fragment
             <TextView/>        /
        </FrameLayout>          )
    
    </SwipeRefreshLayout>
    

    So the SwipeRefreshLayout was choosing the FrameLayout as it's "target" and its default canChildScrollUp() implementation was always returning false. Once I moved the SwipeRefreshLayout inside the Fragment, everything started working correctly.

    <FrameLayout>
    
        <SwipeRefreshLayout>    )
             <ListView/>        \ fragment
             <TextView/>        /
        </SwipeRefreshLayout>   )
    
    </FrameLayout>
    
    0 讨论(0)
  • 2020-12-01 10:58

    Even simpler just set SwipeRefreshLayout enabled if firstVisibleItem or disabled if not:

    yourList.setOnScrollListener(new AbsListView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
    
        }
    
        @Override 
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            yourSwipeRefreshLayout.setEnabled(firstVisibleItem == 0);
        }
    });
    
    0 讨论(0)
提交回复
热议问题