ericlokness ericlokness - 1 month ago 9
Android Question

ListView scroll position not maintained after loading content using CWAC Endless Adpater

update

Basically, bbrakenhoff has answered my question but there is just one more thing left to fix. How can I update the contents of my EndlessFeedAdapter (mEndlsFidAdptr)? I need to clear the item and then reload. I'm using the CWAC EndlessAdapater. Is there a trick to clear the contents or would it be easier to just program a method? After this is done the scroll position should be maintaind.




I am getting data from a server and updating my EndlessFeedAdapter when content changes. Each time I am updating my adapter and reloading content. The problem is that after reloading my list jumps right back to the top as my scroll position is not maintained. I have tried setSelection and setSelectionFromTop extensively, but without positive results.

How do I maintain scroll position after the adapter has been updated?

I have been going through the forums searching for an answer but nothing seems to be working.

I have tried all these: Maintain/Save/Restore scroll position when returning to a ListView

This didn't work:

int index = mList.getFirstVisiblePosition();
View v = mList.getChildAt(0);
int top = (v == null) ? 0 : v.getTop();


// restore index and position
mList.setSelectionFromTop(index, top);


Nor this:

// Save ListView state
Parcelable state = listView.onSaveInstanceState();

// Set new items
listView.setAdapter(adapter);

// Restore previous state (including selected item index and scroll position)
listView.onRestoreInstanceState(state);


Nor the other solutions such as setting up a runnable or setting the scrollPositionY. Setting notifyDataChanged didn't work as I am loading from different lists.

My code:

private void showFeed() {

if (mFeedActivity.mInFeed) {
mQuickReturnView.setVisibility(View.VISIBLE);
} else {
mQuickReturnView.setVisibility(View.GONE);
}

Activity actvt= getActivity();
if (actvt == null || mFeedListView == null) return;

actvt.invalidateOptionsMenu();

mFeedListView.setVisibility(View.VISIBLE);

//updated with help from response
if (mAdapter == null){
mAdapter = new FeedAdapter(actvt, 0, mFeed.getItems().getFeedItemList(), this);
} else {
mAdapter.clear();
mAdapter.addAll(mFeed.getItems().getFeedItemList());
mAdapter.notifyDataSetChanged();
}

mEndlsFidAdptr = new EndlessFeedAdapter(actvt, mAdapter, R.layout.progress_row, mFeed.isShowMoreBar(),

mEndlsFidAdptr.setRunInBackground(false);

//Parcelable state = mFeedListView.onSaveInstanceState();
mFeedListView.setAdapter(mEndlsFidAdptr);
//mFeedListView.onRestoreInstanceState(state);



mFeedListView.setSelectionFromTop(mFirstVisibleItem, mVisibleItemOffset);

if(!(mFeedScope.equalsIgnoreCase(FeedScope.BOOKMARKS.xmlValue()) ||
mFeedScope.equalsIgnoreCase(FeedScope.DOCUMENT.xmlValue()) ||
mFeedScope.equalsIgnoreCase(FeedScope.NOTIFICATIONS.xmlValue()) ||
mFeedScope.equalsIgnoreCase(FeedScope.RECEIVED_TASKS.xmlValue()) ||
mFeedScope.equalsIgnoreCase(FeedScope.SEND_TASKS.xmlValue()))) {

mFeedListView.getViewTreeObserver().addOnGlobalLayoutListener(mGlobalLayoutListener);


mFeedListView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {

mCanShowHide = scrollState == SCROLL_STATE_FLING;

}


@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

View v = mFeedListView.getChildAt(0);
//View v = null;
if(!mFeedActivity.mInFeed || v == null)
return;

int top = v.getTop();

if(mIsAnimating) {
mVisibleItemOffset = top;
mFirstVisibleItem = firstVisibleItem;
return;
}

boolean hide = false;
boolean show = false;
float stickyHeight = getResources().getDimension(R.dimen.sticky_height);

if(firstVisibleItem == mFirstVisibleItem) {
if((top + stickyHeight) < mVisibleItemOffset) {
// Content scrolled down
// if shown then hide quickactionview
if(mQuickReturnShown) {
hide = true;
}

} else if (top > mVisibleItemOffset) {
// Content scrolled up
// if hidden then show quickactionview
if(!mQuickReturnShown) {
show = true;
}

}

} else if(firstVisibleItem > mFirstVisibleItem) {
// Content scrolled down
// if shown then hide quickactionview
if(mQuickReturnShown) {
hide = true;
}

} else if (firstVisibleItem < mFirstVisibleItem) {
// Content scrolled up
// if hidden then show quickactionview
if(!mQuickReturnShown) {
show = true;
}
}

if((show && mCanShowHide) || (top == 0 && !mQuickReturnShown)) {
mTranslateAnimation = new TranslateAnimation(0, 0, -mQuickReturnHeight, 0);
mTranslateAnimation.setDuration(DURATION_MILLIS);
mTranslateAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
mIsAnimating = true;
}

@Override
public void onAnimationEnd(Animation animation) {
mIsAnimating = false;
mQuickReturnShown = true;
mQuickReturnView.setVisibility(View.VISIBLE);
}

@Override
public void onAnimationRepeat(Animation animation) {

}
});

mQuickReturnView.startAnimation(mTranslateAnimation);
}

if(hide) {
mTranslateAnimation = new TranslateAnimation(0, 0, 0, -mQuickReturnHeight);
mTranslateAnimation.setDuration(DURATION_MILLIS);
mTranslateAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
mIsAnimating = true;
}

@Override
public void onAnimationEnd(Animation animation) {
mIsAnimating = false;
mQuickReturnShown = false;
mQuickReturnView.setVisibility(View.GONE);
}

@Override
public void onAnimationRepeat(Animation animation) { }
});


mQuickReturnView.startAnimation(mTranslateAnimation);
}

mVisibleItemOffset = top;
mFirstVisibleItem = firstVisibleItem;
}
});
} else {
mFeedListView.setOnScrollListener(null);

}

mFeedListView.setSelectionFromTop(mFirstVisibleItem, mVisibleItemOffset);

//mFeedListView.scrollTo(mCurrentX,mCurrentY);

if(mFeed.getItems().getFeedItemList().size() == 0) {
mEmptyFeedView.setVisibility(View.VISIBLE);
}
}


Any help is appreciated!

Answer

So the solution wasn't the logical place where I was looking. Thanks a lot to bbrakenhoff for pointing me in the right direction!

My class showFeed() was called from another class called downloadFeed() my scroll position wasn't maintained because downloadFeed() was only loading 5 items when it refreshed, hence even if I maintained the correct scroll position it was not visible.

Although it may be a long shot if someone else has this problem - to fix simply create a variable to hold the total size of your scrollable list when the user performs an onClick event. Then when downloadFeed() is called again, there are more items to download instead the default 5. Then the scroll position is able to be maintained as the visible items are now present.

I ended up using mFeedListView.setSelectionFromTop(firstVisibleItem, positionOffset)

Comments