Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android listView find the amount of pixels scrolled

Tags:

android

scroll

I have a listView. When I scroll and stops in a particular place.

How can I get the amount of pixels I scrolled(from top)?

I have tried using get listView.getScrollY(), but it returns 0.

like image 756
ShineDown Avatar asked Dec 12 '11 07:12

ShineDown


1 Answers

I had the same problem.

I cannot use View.getScrollY() because it always returns 0 and I cannot use OnScrollListener.onScroll(...) because it works with positions not with pixels. I cannot subclass ListView and override onScrollChanged(...) because its parameter values are always 0. Meh.

All I want to know is the amount the children (i.e. content of listview) got scrolled up or down. So I came up with a solution. I track one of the children (or you can say one of the "rows") and follow its vertical position change.

Here is the code:

public class ObservableListView extends ListView {

public static interface ListViewObserver {
    public void onScroll(float deltaY);
}

private ListViewObserver mObserver;
private View mTrackedChild;
private int mTrackedChildPrevPosition;
private int mTrackedChildPrevTop;

public ObservableListView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
    super.onScrollChanged(l, t, oldl, oldt);
    if (mTrackedChild == null) {
        if (getChildCount() > 0) {
            mTrackedChild = getChildInTheMiddle();
            mTrackedChildPrevTop = mTrackedChild.getTop();
            mTrackedChildPrevPosition = getPositionForView(mTrackedChild);
        }
    } else {
        boolean childIsSafeToTrack = mTrackedChild.getParent() == this && getPositionForView(mTrackedChild) == mTrackedChildPrevPosition;
        if (childIsSafeToTrack) {
            int top = mTrackedChild.getTop();
            if (mObserver != null) {
                float deltaY = top - mTrackedChildPrevTop;
                mObserver.onScroll(deltaY);
            }
            mTrackedChildPrevTop = top;
        } else {
            mTrackedChild = null;
        }
    }
}

private View getChildInTheMiddle() {
    return getChildAt(getChildCount() / 2);
}

public void setObserver(ListViewObserver observer) {
    mObserver = observer;
}

}

Couple of notes:

  • we override onScrollChanged(...) because it gets called when the listview is scrolled (just its parameters are useless)
  • then we choose a child (row) from the middle (doesn't have to be precisely the child in the middle)
  • every time scrolling happens we calculate vertical movement based on previous position (getTop()) of tracked child
  • we stop tracking a child when it is not safe to be tracked (e.g. in cases where it might got reused)
like image 100
Zsolt Safrany Avatar answered Oct 21 '22 02:10

Zsolt Safrany