ListView로 돌아갈 때 스크롤 위치 유지 / 저장 / 복원 가기 전에 스크롤 할 수 있는

ListView사용자가 이전 화면으로 돌아 가기 전에 스크롤 할 수 있는 시간 이 길었습니다 . 사용자가 이것을 ListView다시 열면 목록이 이전과 같은 지점으로 스크롤되기를 원합니다. 이것을 달성하는 방법에 대한 아이디어가 있습니까?



답변

이 시도:

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

// ...

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

설명 :

ListView.getFirstVisiblePosition()맨 위 표시 목록 항목을 리턴합니다. 그러나이 항목은 부분적으로 스크롤되지 않을 수 있으며 목록의 정확한 스크롤 위치를 복원하려면이 오프셋을 가져와야합니다. 그래서 ListView.getChildAt(0)를 반환 View상위 목록 항목에 대한 다음 View.getTop() - mList.getPaddingTop()의 상단에서 오프셋 상대를 반환 ListView. 그런 다음 ListView스크롤의 스크롤 위치 를 복원하기 위해 ListView.setSelectionFromTop()원하는 항목의 인덱스와 상단의 상단에서 상단 가장자리를 배치하는 오프셋을 호출 합니다 ListView.


답변

Parcelable state;

@Override
public void onPause() {
    // Save ListView state @ onPause
    Log.d(TAG, "saving listview state");
    state = listView.onSaveInstanceState();
    super.onPause();
}
...

@Override
public void onViewCreated(final View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    // Set new items
    listView.setAdapter(adapter);
    ...
    // Restore previous state (including selected item index and scroll position)
    if(state != null) {
        Log.d(TAG, "trying to restore listview state");
        listView.onRestoreInstanceState(state);
    }
}

답변

@ (Kirk Woll)에서 제안한 솔루션을 채택했으며 나에게 효과적입니다. “Contacts”앱의 Android 소스 코드에서도 비슷한 기술을 사용하는 것을 보았습니다. 자세한 내용을 추가하고 싶습니다. ListActivity 파생 클래스에서 맨 위에 :

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

그런 다음 일부 메소드가 대체됩니다.

@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);
}

물론 “loadData”는 DB에서 데이터를 검색하여 목록에 넣는 기능입니다.

내 Froyo 장치에서는 전화 방향을 변경하거나 항목을 편집하고 목록으로 돌아갈 때 모두 작동합니다.


답변

매우 간단한 방법 :

/** Save the position **/
int currentPosition = listView.getFirstVisiblePosition();

//Here u should save the currentPosition anywhere

/** Restore the previus saved position **/
listView.setSelection(savedPosition);

setSelection 메소드 는 목록을 제공된 항목으로 재설정합니다. 터치 모드가 아닌 경우 터치 모드에서 항목이 화면에만 배치되는 경우 실제로 항목이 선택됩니다.

더 복잡한 접근법 :

listView.setOnScrollListener(this);

//Implements the interface:
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
    mCurrentX = view.getScrollX();
    mCurrentY = view.getScrollY();
}

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {

}

//Save anywere the x and the y

/** Restore: **/
listView.scrollTo(savedX, savedY);

답변

나는 이것에 대해 흥미로운 것을 발견했다.

나는 setSelection과 scrolltoXY를 시도했지만 전혀 작동하지 않았다. 일부 시행 착오 후에 목록이 같은 위치에 남아 있었다. 다음 코드가 작동한다.

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

Runnable을 게시하는 대신 runOnUiThread를 시도해도 작동하지 않습니다 (적어도 일부 장치에서는)

이것은 똑바로 나아가 야 할 무언가에 대한 매우 이상한 해결 방법입니다.


답변

주의!! AbsListView에는 ListView.getFirstVisiblePosition ()이 0 인 경우 onSaveState ()가 올바르게 작동하지 않는 버그가 있습니다.

따라서 대부분의 화면을 차지하는 큰 이미지가 있고 두 번째 이미지로 스크롤하지만 첫 번째 이미지 중 일부가 표시되면 스크롤 위치가 저장되지 않습니다 …

에서 AbsListView.java:1650 (주석 광산)

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

그러나이 상황에서 아래 코드의 ‘상단’은 음수로 표시되어 상태를 올바르게 복원하지 못하게하는 다른 문제가 발생합니다. 따라서 ‘상단’이 음수이면 다음 아이를 얻습니다.

// 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);

답변

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);
        }
    }
}

충분 해