如何在ExpandableListView中保留滚动位置

时间:2011-04-19 08:27:23

标签: android

在我的应用程序中,我有一个派生自ExpandableListActivity的类。 当我滚动内容,然后更改手机方向或编辑项目,然后返回列表时,不保留原始列表位置。 我尝试了两种解决方案,类似于我最近成功使用的ListActivity派生类。

解决方案1:

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

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

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

解决方案2:

protected void onRestoreInstanceState(Bundle state) {
    super.onRestoreInstanceState(state);
    mListPosition = state.getInt(LIST_STATE);
}

protected void onResume() {
    super.onResume();
    loadData();
    getExpandableListView().setSelection(mListPosition);
}

protected void onSaveInstanceState(Bundle state) {
    super.onSaveInstanceState(state);
    mListPosition = getExpandableListView().getFirstVisiblePosition();
    state.putInt(LIST_STATE, mListPosition);
}

两种解决方案都不起作用。我也尝试将两种解决方案结合起来,这在我编辑项目并返回列表时起作用,但是当我改变手机方向时它不起作用

任何人都可以建议一个实现目标的好方法吗?

4 个答案:

答案 0 :(得分:21)

经过几次实验后,我得到了一个令人满意的解决方案,它也保留了顶部可见项目的精细滚动位置。

事实上,需要保存和恢复三个不同的信息:列表状态(例如扩展哪些组),第一个可见项的索引及其精细滚动位置。

不幸的是,似乎只有第一个由可扩展列表视图的onSaveInstanceState方法保存,因此其他两个需要单独保存。这与不可扩展的列表视图不同,在该视图中,onSaveInstanceState方法会保存正确恢复列表状态和位置所需的所有信息(关于此主题,请参阅Maintain/Save/Restore scroll position when returning to a ListView)。

以下是代码段;在ExpandableListActivity派生类之上:

private static final String LIST_STATE_KEY = "listState";
private static final String LIST_POSITION_KEY = "listPosition";
private static final String ITEM_POSITION_KEY = "itemPosition";

private Parcelable mListState = null;
private int mListPosition = 0;
private int mItemPosition = 0;

然后,一些覆盖:

protected void onRestoreInstanceState(Bundle state) {
    super.onRestoreInstanceState(state);

    // Retrieve list state and list/item positions
    mListState = state.getParcelable(LIST_STATE_KEY);
    mListPosition = state.getInt(LIST_POSITION_KEY);
    mItemPosition = state.getInt(ITEM_POSITION_KEY);
}

protected void onResume() {
    super.onResume();

    // Load data from DB and put it onto the list
    loadData();

    // Restore list state and list/item positions
    ExpandableListView listView = getExpandableListView();
    if (mListState != null)
        listView.onRestoreInstanceState(mListState);
    listView.setSelectionFromTop(mListPosition, mItemPosition);
}

protected void onSaveInstanceState(Bundle state) {
    super.onSaveInstanceState(state);

    // Save list state
    ExpandableListView listView = getExpandableListView();
    mListState = listView.onSaveInstanceState();
    state.putParcelable(LIST_STATE_KEY, mListState);

    // Save position of first visible item
    mListPosition = listView.getFirstVisiblePosition();
    state.putInt(LIST_POSITION_KEY, mListPosition);

    // Save scroll position of item
    View itemView = listView.getChildAt(0);
    mItemPosition = itemView == null ? 0 : itemView.getTop();
    state.putInt(ITEM_POSITION_KEY, mItemPosition);
}

这在我的Froyo设备上运行良好。

答案 1 :(得分:6)

这就是我使ExpandableListView.onRestoreInstanceState和onSaveInstanceState工作的方式......

如果您使用的是BaseExpandableListAdapter,则getCombinedChildId的默认实现会返回一个负数。如果您查看从保存的状态滚动位置恢复列表的代码,它会忽略负数的ID。返回正ID,以便AbsListView onRestoreInstanceState正确设置滚动位置。要返回正ID,请通过覆盖BaseExpandableListAdapter子类中的方法将getCombinedChildId或0x8000000000000000L(负数)更改为0x7000000000000000L(正数),如下所示...

        public long getCombinedChildId(long groupId, long childId)
        {
            long or  = 0x7000000000000000L;
            long group = (groupId & 0x7FFFFFFF) << 32;
            long child = childId & 0xFFFFFFFF;
            return or | group | child;
        }

答案 2 :(得分:0)

我发现另一种方法可以帮助我维持状态。这是链接。

http://markmail.org/message/msesxums77bdoqnx#query:+page:1+mid:utmart4ob7flh3u7+state:results

总结是你总是要设置状态,即使convertView!= null。

我不知道总是设置状态的影响,但在我看来它完美无缺。

答案 3 :(得分:-2)

要在更改手机方向时阻止重新加载您的活动,只需将以下行添加到活动部分的AndroidManifest.xml中:

        android:configChanges="keyboardHidden|orientation|screenSize"