Android getting exact scroll position in ListView

I'd like to get the exact, pixel position of the ListView scroll. And no, I am not referring to the first visible position.

Is there a way to achieve this?


Solution 1:

Okay, I found a workaround, using the following code:

View c = listview.getChildAt(0);
int scrolly = -c.getTop() + listview.getFirstVisiblePosition() * c.getHeight();

The way it works is it takes the actual offset of the first visible list item and calculates how far it is from the top of the view to determine how much we are "scrolled into" the view, so now that we know that we can calculate the rest using the regular getFirstVisiblePosition method.

Solution 2:

Saarraz1's answer will only work if all the rows in the listview are of the same height and there's no header (or it is also the same height as the rows).

Note that once the rows disappear at the top of the screen you don't have access to them, as in you won't be able to keep track of their height. This is why you need to save those heights (or accumulated heights of all). My solution requires keeping a Dictionary of heights per index (it is assumed that when the list is displayed the first time it is scrolled to the top).

private Dictionary<Integer, Integer> listViewItemHeights = new Hashtable<Integer, Integer>();

private int getScroll() {
    View c = listView.getChildAt(0); //this is the first visible row
    int scrollY = -c.getTop();
    listViewItemHeights.put(listView.getFirstVisiblePosition(), c.getHeight());
    for (int i = 0; i < listView.getFirstVisiblePosition(); ++i) {
        if (listViewItemHeights.get(i) != null) // (this is a sanity check)
            scrollY += listViewItemHeights.get(i); //add all heights of the views that are gone
    }
    return scrollY;
}

Solution 3:

Simplest idea I could come up with was to extend ListView and expose the "computeVerticalScrollOffset" which is protected by default, then use "com.your.package.CustomListView" in your xml layouts.

public class CustomListView extends ListView {

    public CustomListView(Context context) {
        super(context);
    }

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

    public CustomListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public int computeVerticalScrollOffset() {
        return super.computeVerticalScrollOffset();
    }
}

Solution 4:

First Declare your int variable for hold the position.

int position = 0;

then add scrollListener to your ListView,

listView.setOnScrollListener(new OnScrollListener() {

        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            // TODO Auto-generated method stub

        }

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

        }
    });

Then after getting new data or any changes in your data that time you need to set the listview current position

listView.setSelection(position);

I have used after setup my adapter , works fine for me..