Maintain/Save/Restore scroll position when returni

2018-12-31 02:38发布

I have a long ListView that the user can scroll around before returning to the previous screen. When the user opens this ListView again, I want the list to be scrolled to the same point that it was previously. Any ideas on how to achieve this?

17条回答
爱死公子算了
2楼-- · 2018-12-31 03:04

I adopted the solution suggested by @(Kirk Woll), and it works for me. I have also seen in the Android source code for the "Contacts" app, that they use a similar technique. I would like to add some more details: On top on my ListActivity-derived class:

private static final String LIST_STATE = "listState";
private Parcelable mListState = null;

Then, some method overrides:

@Override
protected void onRestoreInstanceState(Bundle state) {
    super.onRestoreInstanceState(state);
    mListState = state.getParcelable(LIST_STATE);
}

@Override
protected void onResume() {
    super.onResume();
    loadData();
    if (mListState != null)
        getListView().onRestoreInstanceState(mListState);
    mListState = null;
}

@Override
protected void onSaveInstanceState(Bundle state) {
    super.onSaveInstanceState(state);
    mListState = getListView().onSaveInstanceState();
    state.putParcelable(LIST_STATE, mListState);
}

Of course "loadData" is my function to retrieve data from the DB and put it onto the list.

On my Froyo device, this works both when you change the phone orientation, and when you edit an item and go back to the list.

查看更多
谁念西风独自凉
3楼-- · 2018-12-31 03:05
private Parcelable state;
@Override
public void onPause() {
    state = mAlbumListView.onSaveInstanceState();
    super.onPause();
}

@Override
public void onResume() {
    super.onResume();

    if (getAdapter() != null) {
        mAlbumListView.setAdapter(getAdapter());
        if (state != null){
            mAlbumListView.requestFocus();
            mAlbumListView.onRestoreInstanceState(state);
        }
    }
}

That's enough

查看更多
残风、尘缘若梦
4楼-- · 2018-12-31 03:06

CAUTION!! There is a bug in AbsListView that doesn't allow the onSaveState() to work correctly if the ListView.getFirstVisiblePosition() is 0.

So If you have large images that take up most of the screen, and you scroll to the second image, but a little of the first is showing, the scroll position Won't be saved...

from AbsListView.java:1650 (comments mine)

// this will be false when the firstPosition IS 0
if (haveChildren && mFirstPosition > 0) {
    ...
} else {
    ss.viewTop = 0;
    ss.firstId = INVALID_POSITION;
    ss.position = 0;
}

But in this situation, the 'top' in the code below will be a negative number which causes other issues that prevent the state to be restored correctly. So when the 'top' is negative, get the next child

// save index and top position
int index = getFirstVisiblePosition();
View v = getChildAt(0);
int top = (v == null) ? 0 : v.getTop();

if (top < 0 && getChildAt(1) != null) {
    index++;
    v = getChildAt(1);
    top = v.getTop();
}
// parcel the index and top

// when restoring, unparcel index and top
listView.setSelectionFromTop(index, top);
查看更多
泛滥B
5楼-- · 2018-12-31 03:12

Am posting this because I am surprised nobody had mentioned this.

After user clicks the back button he will return to the listview in the same state as he went out of it.

This code will override the "up" button to behave the same way as the back button so in the case of Listview -> Details -> Back to Listview (and no other options) this is the simplest code to maintain the scrollposition and the content in the listview.

 public boolean onOptionsItemSelected(MenuItem item) {
     switch (item.getItemId()) {
         case android.R.id.home:
             onBackPressed();
             return(true);
     }
     return(super.onOptionsItemSelected(item)); }

Caution: If you can go to another activity from the details activity the up button will return you back to that activity so you will have to manipulate the backbutton history in order for this to work.

查看更多
孤独总比滥情好
6楼-- · 2018-12-31 03:14

I found something interesting about this.

I tried setSelection and scrolltoXY but it did not work at all, the list remained in the same position, after some trial and error I got the following code that does work

final ListView list = (ListView) findViewById(R.id.list);
list.post(new Runnable() {            
    @Override
    public void run() {
        list.setSelection(0);
    }
});

If instead of posting the Runnable you try runOnUiThread it does not work either (at least on some devices)

This is a very strange workaround for something that should be straight forward.

查看更多
登录 后发表回答