Detecting The Scrolling Direction in The Adapter (Up/Down)

Detecting the scrolling direction in the adapter (up/down)

This is the easiest and simplest method I came across. And it works like a charm.

view.addOnScrollListener(new View.OnScrollListener() {
@Override
public void onScrolled(@NonNull View view, int dx, int dy) {
if (dy > 0) {
//Scrolling down
} else if (dy < 0) {
//Scrolling up
}
}
});

RecyclerView scrolled UP/DOWN listener

Try this way:

private static int firstVisibleInListview;

firstVisibleInListview = yourLayoutManager.findFirstVisibleItemPosition();

In your scroll listener:

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

int currentFirstVisible = yourLayoutManager.findFirstVisibleItemPosition();

if(currentFirstVisible > firstVisibleInListview)
Log.i("RecyclerView scrolled: ", "scroll up!");
else
Log.i("RecyclerView scrolled: ", "scroll down!");

firstVisibleInListview = currentFirstVisible;

}

How to detect if a listview is scrolling up or down in android?

this is a simple implementation:

lv.setOnScrollListener(new OnScrollListener() {

private int mLastFirstVisibleItem;

@Override
public void onScrollStateChanged(AbsListView view, int scrollState){}

@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {

if(mLastFirstVisibleItem < firstVisibleItem){
// Scrolling down
}
if(mLastFirstVisibleItem > firstVisibleItem){
// scrolling up
}
mLastFirstVisibleItem = firstVisibleItem;
}
});

how to detect up-scrolling in listview

API provides such methods, but they are protected, so the best practice in my opinion, is to create wrapper class (extend ScrollView) and make those methods public, particularly onScrollChanged and onOverScroll.

You may look at the following questions to see how to do this:

http://pastebin.com/ePeyswyQ

Detecting the scrolling direction in the adapter (up/down)

Detect start scroll and end scroll in recyclerview

step 1 You can create a class extending RecyclerView.OnScrollListener and override these methods

public class CustomScrollListener extends RecyclerView.OnScrollListener {
public CustomScrollListener() {
}

public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
switch (newState) {
case RecyclerView.SCROLL_STATE_IDLE:
System.out.println("The RecyclerView is not scrolling");
break;
case RecyclerView.SCROLL_STATE_DRAGGING:
System.out.println("Scrolling now");
break;
case RecyclerView.SCROLL_STATE_SETTLING:
System.out.println("Scroll Settling");
break;

}

}

public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (dx > 0) {
System.out.println("Scrolled Right");
} else if (dx < 0) {
System.out.println("Scrolled Left");
} else {
System.out.println("No Horizontal Scrolled");
}

if (dy > 0) {
System.out.println("Scrolled Downwards");
} else if (dy < 0) {
System.out.println("Scrolled Upwards");
} else {
System.out.println("No Vertical Scrolled");
}
}
}

step 2- Since setOnScrollListener is deprecated It is better to use addOnScrollListener

 mRecyclerView.addOnScrollListener(new CustomScrollListener());

how to check scroll bottom and top

Have you try scrollView.fullScroll(ScrollView.FOCUS_UP); and scrollView.fullScroll(ScrollView.FOCUS_DOWN);

how to tell if user swipe down or up when recyclerview cannot be scrolled

To solve this problem we create a new TouchInterceptRecyclerView and we use a gesture detector as below.

public class TouchInterceptRecyclerView extends RecyclerView {

private final GestureDetector gestureDetector;

public TouchInterceptRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
this.gestureDetector = new GestureDetector(context, createGestureListener());
}

private GestureDetector.OnGestureListener createGestureListener() {
return new GestureDetector.SimpleOnGestureListener() {

@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
// Based on the 2 motions calculate direction of motion.
// For horizontal scroll we need to find if the scroll direction is
// left or right based on which we add our business logic.
return false;
}
};
}

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
gestureDetector.onTouchEvent(ev);
// This dispatches the event downstream to children.
// We need this to handle things like item click.
return super.dispatchTouchEvent(ev);
}

Now we need to find scroll direction inside #onScroll().
For that we refer the answer here

Now adding that code to calculate direction to our above code, we get:

public class TouchInterceptRecyclerView extends RecyclerView {

private final GestureDetector gestureDetector;

public TouchInterceptRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
this.gestureDetector = new GestureDetector(context, createGestureListener());
}

private GestureDetector.OnGestureListener createGestureListener() {
return new GestureDetector.SimpleOnGestureListener() {

@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (e1 == null || e2 == null) {
return false;
}
float x1 = e1.getX();
float y1 = e1.getY();

float x2 = e2.getX();
float y2 = e2.getY();

Direction direction = getDirection(x1, y1, x2, y2);
return onSwipe(direction);
}

private boolean onSwipe(Direction direction) {
if (direction == Direction.left || direction == Direction.right) {
// Handle business logic starting here. <------
Log.d("#########", direction.toString());
}
return false;
}

private Direction getDirection(float x1, float y1, float x2, float y2) {
double angle = getAngle(x1, y1, x2, y2);
return Direction.fromAngle(angle);
}

private double getAngle(float x1, float y1, float x2, float y2) {
double rad = Math.atan2(y1 - y2, x2 - x1) + Math.PI;
return (rad * 180 / Math.PI + 180) % 360;
}
};
}

public enum Direction {
up,
down,
left,
right;

public static Direction fromAngle(double angle) {
if (inRange(angle, 45, 135)) {
return Direction.up;
} else if (inRange(angle, 0, 45) || inRange(angle, 315, 360)) {
return Direction.right;
} else if (inRange(angle, 225, 315)) {
return Direction.down;
} else {
return Direction.left;
}

}

private static boolean inRange(double angle, float init, float end) {
return (angle >= init) && (angle < end);
}
}

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
gestureDetector.onTouchEvent(ev);
// This dispatches the event downstream to children. We need this to handle things like item click.
return super.dispatchTouchEvent(ev);
}
}

Now only thing left is that we only have to use the gesture detector if all items are completely visible on screen.
For that we introduce another method in the TouchInterceptRecyclerView called areAllItemsCompletelyWithinViewPort().
The updated code snippet is below:

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if(areAllItemsCompletelyWithinViewPort()) {
gestureDetector.onTouchEvent(ev);
}
// This dispatches the event downstream to children. We need this to handle things like item click.
return super.dispatchTouchEvent(ev);
}

private boolean areAllItemsCompletelyWithinViewPort() {
if (getAdapter() == null) {
return false;
}
LayoutManager layoutManager = getLayoutManager();
int firstItemPosition = 0;
int lastItemPosition = 0;
if (layoutManager instanceof LinearLayoutManager) {
firstItemPosition = ((LinearLayoutManager) layoutManager).findFirstCompletelyVisibleItemPosition();
lastItemPosition = ((LinearLayoutManager) layoutManager).findLastCompletelyVisibleItemPosition();
}
return firstItemPosition == 0 && lastItemPosition == getAdapter().getItemCount() - 1;
}

I actually tried it with a horizontal scrolling recycler view and it works well. You can easily use it for vertical scrolling one.



Related Topics



Leave a reply



Submit