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?
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.
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.
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 :)
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);
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
}
}