如何在ExpandableListView中保留滚动位置

问题描述

| 在我的应用程序中,我有一个从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);
}
两种解决方案均无效。我也尝试将两种解决方案结合起来,当我编辑一个项目并返回到列表时,此方法有效,但是当我更改手机方向时,它不起作用 任何人都可以提出实现我的目标的好方法吗?

解决方法

经过几次实验,我得出了令人满意的解决方案,该方案还保留了顶部可见项的精细滚动位置。 实际上,需要保存和恢复三个不同的信息:列表状态(例如,扩展了哪些组),第一个可见项目的索引及其精细滚动位置。 不幸的是,似乎只有第一个是通过可扩展列表视图的onSaveInstanceState方法保存的,因此其他两个需要分别保存。这与不可扩展的列表视图不同,后者显示onSaveInstanceState方法保存正确还原列表的状态和位置所需的所有信息(关于此主题,请返回返回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设备上可以正常工作。,这就是我使ExpandableListView.onRestoreInstanceState和onSaveInstanceState工作的方式... 如果您使用的是BaseExpandableListAdapter,则getCombinedChildId的默认实现将返回负数。如果您查看用于从保存状态滚动位置还原列表的代码,它将忽略ID为负的ID。返回正ID,以便AbsListView onRestoreInstanceState将正确设置滚动位置。要返回正ID,请通过重写BaseExpandableListAdapter子类中的方法,将getCombinedChildId的or从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;
        }
,我找到了另一种方法来保持状态。链接在这里。 http://markmail.org/message/msesxums77bdoqnx#query:+page:1+mid:utmart4ob7flh3u7+state:结果 总结是,即使convertView!= null,也始终必须设置状态。 我不知道总是设置状态的影响,但是就我而言,它可以完美地工作。,为了防止在更改手机方向时重新加载活动,只需在活动部分中将以下行添加到AndroidManifest.xml中:
        android:configChanges=\"keyboardHidden|orientation|screenSize\"