Loading list item at top of listview without losing scroll position
It seemed very easy for me when I started doing it. But later I realised it is no more easy. Adding an item in listview is an ordinary process but keeping the scroll position is a challenge. I did a small research on this but could not find any thing useful. Until I encountered this SO post. It directed me to this amazing link of Chris banes. The following video shows the required final output I achieved.
Problem,
Whenever we add an item and call
adapter.notifyDataSetChanged();
it refresh the listview with new items and hence we lose our current scroll position.
Solution,
While adding new item into a listview, inorder to stop flicking scroll position we need to block laying out children layout of listview. This can be achieved by creating a custom listview.
public class StoryListView extends ListView {
private boolean blockLayoutChildren;
public StoryListView(Context context) {
super(context);
}
public StoryListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setBlockLayoutChildren(boolean blockLayoutChildren) {
this.blockLayoutChildren = blockLayoutChildren;
}
@Override
protected void layoutChildren() {
if (!blockLayoutChildren) {
super.layoutChildren();
}
}
}
All we need is to set and unset
blockLayoutChildren
boolean while adding an item.
// get first visible position of the list view
int firstVisPos = listView.getFirstVisiblePosition();// get child view at visible 0th position of the listview
View firstVisView = listView.getChildAt(0);// set top in pixel of the child view
int top = firstVisView != null ? firstVisView.getTop() : 0;// block from laying child layout
listView.setBlockLayoutChildren(true);// add new item to the collection
items.add(0, “New Story “ + count++);// no. of items added in list before firstVisible item — it is ‘1’ in our case
int itemsAddedBeforeFirstVisible = 1;// notify the adapter
adapter.notifyDataSetChanged();// un block from laying child layout
listView.setBlockLayoutChildren(false);// finally set item selection
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
listView.setSelectionFromTop(firstVisPos + itemsAddedBeforeFirstVisible, top);
} else {
listView.setSelection(firstVisPos + itemsAddedBeforeFirstVisible);
}
Code above is self explanatory. The full source code is available in GitHub.
Happy Coding!