Android ListView - scrolls back to top on update

2020-02-07 02:42发布

问题:

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?

回答1:

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.



回答2:

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.



回答3:

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 :)



回答4:

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);


回答5:

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
    }
}