6

I have a listview that gets additional views added on request, that's maintained by a BaseAdapter. How can I maintain scroll position after the update?

I know this has been asked a few times, but each time, the same solution has been put forward, which I have tried, which is to call adapter.notifyDataSetChanged(); after updating the ArrayList that contains the list contents.

How can I ensure that scroll position is maintained?

ajacian81
  • 7,419
  • 9
  • 51
  • 64

5 Answers5

12

Implement an OnScrollListener in your activity class and then use the following code:

int currentFirstVisibleItem, currentVisibleItemCount, currentTotalItemCount;
public void onScroll(AbsListView view, int firstVisibleItem,
        int visibleItemCount, int totalItemCount) {
    this.currentFirstVisibleItem = firstVisibleItem;
    this.currentVisibleItemCount = visibleItemCount;
    this.currentTotalItemCount = totalItemCount;
}

public void onScrollStateChanged(AbsListView view, int scrollState) {
    this.currentScrollState = scrollState;
    this.isScrollCompleted();
}

private void isScrollCompleted() {

    if (currentFirstVisibleItem + currentVisibleItemCount >= currentTotalItemCount) {
        if (this.currentVisibleItemCount > 0
                && this.currentScrollState == SCROLL_STATE_IDLE) {

            //Do your work
        }
    }
}

If you are using AsyncTask for updating your data, then you can include the following in your PostExecute() in order to maintain the Scroll position:

list.setAdapter(adapter);
list.setSelectionFromTop(currentFirstVisibleItem, 0);

I hope this helps.

Shekhar Chikara
  • 3,786
  • 2
  • 29
  • 52
  • what do you mean by //Do your work. What else would there be to do? – ajacian81 Aug 14 '12 at 22:14
  • In //Do your work, you can write your code like whatever you want to do on scroll completion.. For example, like Facebook if you want to load more data on Scroll down, you can write the code for that here.. – Shekhar Chikara Aug 15 '12 at 08:12
  • This work fine for adding footer...I what to add a header to my listview for refresh. So please give me a condition to add the header to the listview – Arun PS Jun 20 '13 at 12:33
  • Thank you very much.. this is one of the ages bug i have – Faruk Oct 21 '16 at 04:20
5

The approach I take is to call ListView.setSelection(position) to scroll to the desired position after the update.

Depending on where you're calling it from, you might need to call requestFocusFromTouch before calling setSelection in order to ensure the item gets positioned appropriately.

Code Poet
  • 11,227
  • 19
  • 64
  • 97
4

This code will help you out....

// get position of listview
int index = listView.getFirstVisiblePosition();
View v = listView.getChildAt(0);
int top = (v == null) ? 0 : v.getTop();

// notify dataset changed or re-assign adapter here

//re-assign the position of listview after setting the adapter again
listView.setSelectionFromTop(index, top);

Cheers :)

Salmaan
  • 3,543
  • 8
  • 33
  • 59
  • Flawless, it's as if the adapter never changed, other than updating the relevant view, which in my case toggles the clicked image in the list layout! Many thanks!! – WallyHale Jan 31 '17 at 10:54
1

You can try this:

//Get the top position from the first visible element
int fVisible = list.getFirstVisiblePosition();
View vFirst = list.getChildAt(0);
int pos = 0;
if (vFirst != null) pos = vFirst.getTop();

//Restore the position
list.setSelectionFromTop(fVisible, pos);
Shekhar Chikara
  • 3,786
  • 2
  • 29
  • 52
  • Unfortunately, amazingly that didn't work. After putting in logging, after scrolling to the desired position, it just reset the position and went back to top. – ajacian81 Aug 12 '12 at 13:33
0

You can do as below. If you want to load more data with scroll to bottom it will have some change.

int currentFirstVisibleItem, currentScrollState;
int countChange = 0;
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    Log.d("Scroll", "Scrolling");
    this.currentFirstVisibleItem = firstVisibleItem;
    countChange = 0;//during touching you can decide not to refresh by scroll
}

public void onScrollStateChanged(AbsListView view, int scrollState) {
    Log.d("Scroll", "Changed");
    this.currentScrollState = scrollState;
    if (scrollState == SCROLL_STATE_TOUCH_SCROLL) {
        countChange = 0;
    }
    if (++countChange > 1) {
        //scroll to top and release touch change=2. Simple scroll and release touch change=1
        this.isScrollCompleted();
        countChange = 0;
    }
}

private void isScrollCompleted() {
    Log.d("Load", "Reload");
    if (currentFirstVisibleItem == 0) {
        //Your loading go here
    }
}
Sarith Nob
  • 43
  • 8
  • Yes, this this is the form of code not picture. I just have tried to write as code. It's not a usual writing as the code in IDE. – Sarith Nob Apr 26 '17 at 07:31