Android ListView - scrolls back to top on update
Asked Answered
N

5

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?

Necessity answered 9/8, 2012 at 6:26 Comment(0)
R
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.

Ramentum answered 13/8, 2012 at 10:29 Comment(4)
what do you mean by //Do your work. What else would there be to do?Necessity
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..Ramentum
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 listviewPrevention
Thank you very much.. this is one of the ages bug i haveJourney
L
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.

Lubbock answered 9/8, 2012 at 6:35 Comment(2)
The call to requestFocusFromTouch was the crucial missing step for me!Cadent
YESSSSSSSSSSS, I would hug you if I could. So long to fix this issueOffense
P
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 :)

Penetrating answered 13/1, 2015 at 5:29 Comment(1)
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!!Blazon
R
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);
Ramentum answered 9/8, 2012 at 6:40 Comment(1)
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.Necessity
E
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
    }
}
Else answered 26/4, 2017 at 6:50 Comment(1)
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.Else

© 2022 - 2024 — McMap. All rights reserved.