I have a ListView
having fastScroll
always enabled and SwipeRefresh
implementation. When i swipe the list downward, i
I just looked into the documentation of the SwipeRefreshLayout
and I think they mention what you are looking for:
... If the listener determines there should not be a refresh, it must call
setRefreshing(false)
to cancel any visual indication of a refresh. If an activity wishes to show just the progress animation, it should callsetRefreshing(true)
. To disable the gesture and progress animation, callsetEnabled(false)
on the view.
So you have a few options, I would first try playing around with setEnabled()
or setRefreshing()
, but to properly use those methods we first need to be able to detect if the ListView
is fast scrolling. There is no listener or anything for fast scrolling but you can get the state through reflection! Based on this excellent and seriously underrated answer I have written a FastScrollListener
which can be used just like a OnScrollListener
:
this.listView.setFastScrollEnabled(true);
this.listView.setOnScrollListener(new FastScrollListener(this.listView) {
@Override
protected void onFastScrollStateChanged(AbsListView view, FastScrollState state) {
// This line disabled the SwipeRefreshLayout
// whenever the user is fast scrolling
swipeRefreshLayout.setEnabled(state != FastScrollState.DRAGGING);
}
@Override
protected void onFastScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
});
You could also try calling setRefreshing()
instead of setEnabled()
if setEnabled()
doesn't work.
And here is the code of the FastScrollListener
:
public abstract class FastScrollListener implements AbsListView.OnScrollListener {
private final int STATE_DRAGGING;
private final int STATE_VISIBLE;
private final int STATE_NONE;
public enum FastScrollState {
DRAGGING,
VISIBLE,
NONE,
UNKNOWN
}
private FastScrollState fastScrollState = FastScrollState.UNKNOWN;
private Field stateField;
private Object mFastScroller;
public FastScrollListener(AbsListView listView) {
try {
final Field fastScrollerField = AbsListView.class.getDeclaredField("mFastScroller");
fastScrollerField.setAccessible(true);
mFastScroller = fastScrollerField.get(listView);
final Field stateDraggingField = mFastScroller.getClass().getDeclaredField("STATE_DRAGGING");
stateDraggingField.setAccessible(true);
STATE_DRAGGING = stateDraggingField.getInt(mFastScroller);
final Field stateVisibleField = mFastScroller.getClass().getDeclaredField("STATE_VISIBLE");
stateVisibleField.setAccessible(true);
STATE_VISIBLE = stateVisibleField.getInt(mFastScroller);
final Field stateNoneField = mFastScroller.getClass().getDeclaredField("STATE_NONE");
stateNoneField.setAccessible(true);
STATE_NONE = stateNoneField.getInt(mFastScroller);
stateField = mFastScroller.getClass().getDeclaredField("mState");
stateField.setAccessible(true);
fastScrollState = getFastScrollState();
} catch (NoSuchFieldException e) {
throw new IllegalStateException("Could not find required fields for fast scroll detection!", e);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Could not find required fields for fast scroll detection!", e);
}
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
updateFastScrollState(view);
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
updateFastScrollState(view);
updateFastScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
}
private void updateFastScrollState(AbsListView view) {
if (stateField != null) {
final FastScrollState state = getFastScrollState();
if (fastScrollState != state) {
fastScrollState = state;
onFastScrollStateChanged(view, state);
}
}
}
private void updateFastScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if(fastScrollState == FastScrollState.DRAGGING) {
onFastScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
}
}
private FastScrollState getFastScrollState() {
try {
final int state = stateField.getInt(mFastScroller);
if (state == STATE_DRAGGING) {
return FastScrollState.DRAGGING;
}
if (state == STATE_VISIBLE) {
return FastScrollState.VISIBLE;
}
if (state == STATE_NONE) {
return FastScrollState.NONE;
}
return FastScrollState.UNKNOWN;
} catch (IllegalAccessException e) {
throw new IllegalStateException("Could not read fast scroll state!", e);
}
}
protected abstract void onFastScrollStateChanged(AbsListView view, FastScrollState state);
protected abstract void onFastScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount);
}
I hope I could help you and if you have any further questions please feel free to ask!
EDIT: Try this, but I doubt it will work:
@Override
protected void onFastScrollStateChanged(AbsListView view, FastScrollState state) {
boolean enable = false;
if (getListView().getChildCount() > 0) {
boolean firstItemVisible = getListView().getFirstVisiblePosition() == 0;
boolean topOfFirstItemVisible = getListView().getChildAt(0).getTop() == 0;
enable = firstItemVisible && topOfFirstItemVisible;
}
refreshLayout.setEnabled(enable);
}
Fast scroll in recyclerveiew was added in api 26. https://developer.android.com/topic/libraries/support-library/revisions#26-0-0.
If you want to use it pre api 26 use
https://github.com/L4Digital/FastScroll
This library has builtin fastscroll and it has a scroll listener that can disable the refreshview layout on scrolling
The developer addresses the problem here:
https://github.com/L4Digital/FastScroll/issues/14