ListView로 돌아갈 때 스크롤 위치 유지 / 저장 / 복원


397

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


22
Eugene Mymrin / Giorgio Barchiesi가 언급 한 솔루션이 허용 된 답변보다 낫다고 생각합니다.
Mira Weller

답변:


631

이 시도:

// 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.


2
이것이 어떻게 작동하는지 실제로 이해하지 못합니다. listView.getFirstVisiblePosition () 만 사용하고 있으며 이해하지만 여기에서 무슨 일이 일어나고 있는지 잘 모르겠습니다. 간단한 설명이 있습니까? :)
HXCaine

56
따라서 ListView.getFirstVisiblePosition ()은 맨 위에 보이는 목록 항목을 반환합니다. 그러나이 항목은 부분적으로 스크롤되지 않을 수 있으며 목록의 정확한 스크롤 위치를 복원하려면이 오프셋을 가져와야합니다. 따라서 ListView.getChildAt (0)은 최상위 목록 항목에 대한 View를 반환 한 다음 View.getTop ()은 ListView의 상단에서 상대 오프셋을 반환합니다. 그런 다음 ListView의 스크롤 위치를 복원하기 위해 원하는 항목의 인덱스와 ListView의 위쪽에서 위쪽 가장자리를 배치하는 오프셋을 사용하여 ListView.setSelectionFromTop ()을 호출합니다. 공습 경보 해제?
이안

15
한 줄만 사용하여 저장 int index = mList.getFirstVisiblePosition();하고 한 줄만 사용하여 복원 하면 훨씬 간단 해집니다 mList.setSelectionFromTop(index, 0);. 그래도 좋은 대답입니다 (+1)! 이 문제에 대한 우아한 해결책을 찾고 있습니다.
Phil

17
@ 단순한 솔루션으로 정확한 스크롤 위치를 복원 할 수 없습니다.
Ixx

2
@nbarraille이 말했듯이 코드는 "v.getTop ()-mList.getPaddingTop ()"과 같은 코드 여야합니다. 그렇지 않으면 당신은 그것이 왜 항상 머리카락을 복원하는지 알아 내려고 노력한 것처럼 한 시간을 보낼 것입니다 ...
jdowdell

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

106
이 방법이 첫 번째 보이는 항목뿐만 아니라 정확한 스크롤 위치를 복원하기 때문에 이것이 가장 좋은 대답이라고 생각합니다 .
Mira Weller

9
큰 대답이지만 동적으로 내용을로드 할 때 작동하지 않으며 onPause () 메서드에 상태를 저장하려고합니다.
Gio

13
훌륭한 솔루션. 하나의 문제. 항목이 크고 스크롤하지만 첫 번째 항목이 여전히 표시되면 목록이 맨 위로 이동합니다. 두 번째 항목이나 다른 곳으로 스크롤하면 모든 것이 작동합니다.
passsy

4
@passsy 목록이 맨 위로 이동하는 솔루션을 찾은 적이 있습니까?
Papajohn000

2
aaronvargas 말했듯이 ListView.getFirstVisiblePosition ()가 0 일 때,이 작동하지 않을 수 있습니다
VinceStyling

54

@ (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 장치에서는 전화 방향을 변경하거나 항목을 편집하고 목록으로 돌아갈 때 모두 작동합니다.


1
이 솔루션은 저에게 효과적이었습니다. 다른 사람들은 그렇지 않았습니다. ListView 인스턴스 상태 저장 / 복원은 ListView에서 항목을 삭제하고 삽입 할 때 어떻게 작동합니까?
Bryan

2
참고로 이것을 조각 (목록 조각을 사용하고 있음)에서 사용하고 다른 조각으로 이동하면 mListState = getListView().onSaveInstanceState().주로 장치 회전 시 호출 할 때 내용보기가 만들어지지 않기 때문에 충돌이 발생합니다 .
Mgamerz

2
onRestoreInstanceState결코 호출되지 않습니다 :(
dVaffection

1
@GiorgioBarchiesi 누구에게 도움이되는 @ (Kirk Wool)은 누구입니까? 사용자는 분명히 자신의 이름을 변경했습니다.
Piovezan

1
예, 그것이 공식적인 종교입니다. 그러나 제 경우에는 데이터가 로컬로로드되고 길이가 매우 제한되어 있으며 순식간에로드되므로 erethic했습니다 :-)
Giorgio Barchiesi

26

매우 간단한 방법 :

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

2
답변에 오류가 있습니다. 이 방법은 setSelection
Janusz

아이디어는 잘 작동하지만 의사 문제가 있습니다. 첫 번째 표시 위치는 약간만 표시 될 수 있으며 (행의 작은 부분 일 수 있음) setSelection ()은 복원이 수행 될 때이 행이 완전히 표시되도록 설정합니다. 만든.
rantravee 2016 년

두 번째 옵션을 살펴보십시오. 난 그냥 내 첫 번째 대답에 추가 한
프란체스코 Laurita에게

27
view.getScrollX () 및 view.getScrollY ()는 항상 0을 반환합니다!
rantravee

3
View.getChildAt () 및 View.getTop ()을 사용하여 위의 (허용되는) 솔루션을 살펴보십시오. ListView는 내부적으로 스크롤을 유지하기 때문에 ListView에서 View.getScrollY ()를 사용할 수 없습니다.
이안

17

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

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

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

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

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


1
나는 같은 문제를 경험했다! 그리고 setSelectionFromTop()작동하지 않습니다.
ofavre

+1. listnew.post ()는 일부 장치에서는 작동하지 않으며 다른 장치에서는 작동하지 않지만 특정 경우에는 작동하지 않지만 runOnUIThread는 정상적으로 작동합니다.
Omar Rehman

@Omar, 작동하지 않는 장치 및 OS의 예를 들어 줄 수 있습니까? 나는 HTC G2 (2.3.4)와 Galaxy Nexus (4.1.2)를 시도했으며 두 가지 모두에서 작동했습니다. 이 스레드의 다른 답변 중 어느 것도 내 장치에서 작동하지 않았습니다.
Dan J

2
listview.post는 4.0.4의 Galaxy Note에서 잘 작동하지만 2.3.6의 Nexus One에서는 작동하지 않습니다. 그러나 onOnUIThread (action)는 두 장치에서 모두 잘 작동합니다.
Omar Rehman

11

주의!! 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);

그것은 매력처럼 작동하지만 완전히 이해하지 못합니다. 첫 번째 항목이 여전히 보이는 경우 다음 아이를 얻는 것이 합리적입니까? 새 인덱스를 사용하여 SelectionFromTop을 설정하면 두 번째 자식부터 목록이 표시되지 않아야합니까? 여전히 첫 번째를 어떻게 보나요?
tafi

@tafi, 첫 번째 항목은 '부분적으로'보일 수 있습니다. 따라서 해당 항목의 상단은 화면 위에 있으므로 음수가됩니다. (이것은 내가 기억하지 못하는 다른 문제를 일으킨다 ...) 그래서 우리는 배치를 위해 두 번째 아이템의 '상단'을 사용합니다. 항상 사용 가능해야합니까? !
aaronvargas 2016 년

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

충분 해


안녕하세요, 위의 코드가 인스턴스 상태가 활동간에 저장되지 않는 RecyclerView 목록을 사용하는 데 도움이됩니까? 다음 질문을 게시했습니다. stackoverflow.com/questions/35413495/… ?
AJW

6

이 문제점에 대한 해결책을 찾고자하는 경우, 문제점의 근원은 목록보기 어댑터를 설정하는 곳일 수 있습니다. 목록보기에서 어댑터를 설정하면 스크롤 위치가 재설정됩니다. 고려해야 할 것. 목록보기에 대한 참조를 얻은 후 어댑터 설정을 onCreateView로 이동하여 문제를 해결했습니다. =)


1

아무도 이것을 언급하지 않았기 때문에 이것을 게시하고 있습니다.

사용자가 뒤로 버튼을 클릭하면 목록에서 나가는 것과 동일한 상태로 목록보기로 돌아갑니다.

이 코드는 "위로"버튼을 무시하여 뒤로 버튼과 동일한 방식으로 작동하므로 Listview-> Details-> Listview로 돌아 가기 (및 다른 옵션은 없음)의 경우 스크롤 위치와 내용을 유지하는 가장 간단한 코드입니다. 목록보기에서.

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

주의 : 세부 사항 활동에서 다른 활동으로 이동할 수있는 경우 위로 단추를 누르면 해당 활동으로 다시 돌아가므로 작동하려면 뒤로 단추 히스토리를 조작해야합니다.



1

가장 좋은 해결책은 :

// 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.post(new Runnable() {
    @Override
    public void run() {
      mList.setSelectionFromTop(index, top);
   }
});

당신은 포스트와 스레드에서 전화해야합니다!


1

다시로드하기 전에 상태를 저장 한 후 다시로드하면 다시로드 한 후 스크롤 상태를 유지할 수 있습니다. 필자의 경우 비동기 네트워크 요청을하고 완료 후 콜백으로 목록을 다시로드했습니다. 이것은 내가 상태를 복원하는 곳입니다. 코드 샘플은 Kotlin입니다.

val state = myList.layoutManager.onSaveInstanceState()

getNewThings() { newThings: List<Thing> ->

    myList.adapter.things = newThings
    myList.layoutManager.onRestoreInstanceState(state)
}

0

액티비티에서 호스팅되는 조각을 사용하는 경우 다음과 같이 할 수 있습니다.

public abstract class BaseFragment extends Fragment {
     private boolean mSaveView = false;
     private SoftReference<View> mViewReference;

     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
          if (mSaveView) {
               if (mViewReference != null) {
                    final View savedView = mViewReference.get();
                    if (savedView != null) {
                         if (savedView.getParent() != null) {
                              ((ViewGroup) savedView.getParent()).removeView(savedView);
                              return savedView;
                         }
                    }
               }
          }

          final View view = inflater.inflate(getFragmentResource(), container, false);
          mViewReference = new SoftReference<View>(view);
          return view;
     }

     protected void setSaveView(boolean value) {
           mSaveView = value;
     }
}

public class MyFragment extends BaseFragment {
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
          setSaveView(true);
          final View view = super.onCreateView(inflater, container, savedInstanceState);
          ListView placesList = (ListView) view.findViewById(R.id.places_list);
          if (placesList.getAdapter() == null) {
               placesList.setAdapter(createAdapter());
          }
     }
}

0

ListView자신의 스크롤 위치를 저장 / 복원하는 경우 이미 안드로이드 프레임 워크에서 이미 구현 된 기능을 복제하고 있습니다. ListView복원 벌금 스크롤 위치 만 아니라 그 자체를 제외하고 한가지주의 : @aaronvargas가에 버그가 언급 한 바와 같이 AbsListView그 첫 번째 목록 항목에 대한 정밀한 스크롤 위치를 복원하지 않습니다가. 그럼에도 불구하고 스크롤 위치를 복원하는 가장 좋은 방법은 스크롤 위치를 복원하지 않는 것입니다. 안드로이드 프레임 워크가 당신을 위해 더 잘 할 것입니다. 다음 조건을 충족하는지 확인하십시오.

  • xml 레이아웃 파일에서 setSaveEnabled(false)메소드를 호출 하지 않고 android:saveEnabled="false"목록의 속성을 설정 하지 않았는지 확인하십시오.
  • 에 대한 ExpandableListView재정의 long getCombinedChildId(long groupId, long childId)방법은 긍정적 인 긴 번호 (클래스의 기본 구현 반환하도록 BaseExpandableListAdapter반환 음수). 예를 들면 다음과 같습니다.

.

@Override
public long getChildId(int groupPosition, int childPosition) {
    return 0L | groupPosition << 12 | childPosition;
}

@Override
public long getCombinedChildId(long groupId, long childId) {
    return groupId << 32 | childId << 1 | 1;
}

@Override
public long getGroupId(int groupPosition) {
    return groupPosition;
}

@Override
public long getCombinedGroupId(long groupId) {
    return (groupId & 0x7FFFFFFF) << 32;
}
  • 경우 ListView또는 ExpandableListView(예컨대 스크린 회전 이후) 여가 활동의 단편을 다시하지 프래그먼트에서 사용된다. findFragmentByTag(String tag)방법으로 조각을 얻습니다 .
  • 있는지 확인하십시오는 ListView을 가지고 android:id있으며 유일하다.

첫 번째 목록 항목으로 위에서 언급 한 경고를 피하기 위해 ListView위치 0에서 특수 더미 0 픽셀 높이보기를 반환하는 방식으로 어댑터를 만들 수 있습니다. 다음은 프로젝트의 간단한 스크롤 위치를 보여 ListView주고 ExpandableListView복원하는 반면 스크롤 위치는 명시 적으로 저장되지 않습니다. / 복원 다른 응용 프로그램으로 임시 전환, 이중 화면 회전 및 테스트 응용 프로그램으로 다시 전환하는 복잡한 시나리오에서도 미세한 스크롤 위치가 완벽하게 복원됩니다. 뒤로 버튼을 눌러 응용 프로그램을 명시 적으로 종료하면 스크롤 위치가 저장되지 않으며 다른 모든 뷰는 상태를 저장하지 않습니다. https://github.com/voromto/RestoreScrollPosition/releases


0

SimpleCursorAdapter를 사용하여 LoaderManager.LoaderCallbacks를 구현하는 ListActivity에서 파생 된 활동의 경우 활동이 거의 항상 다시 시작되고 세부 사항보기가 닫힐 때 어댑터가 다시로드 되었기 때문에 onReset ()에서 위치를 복원하는 작업이 수행되지 않았습니다. 트릭은 onLoadFinished ()에서 위치를 복원하는 것이 었습니다.

onListItemClick ()에서 :

// save the selected item position when an item was clicked
// to open the details
index = getListView().getFirstVisiblePosition();
View v = getListView().getChildAt(0);
top = (v == null) ? 0 : (v.getTop() - getListView().getPaddingTop());

onLoadFinished ()에서 :

// restore the selected item which was saved on item click
// when details are closed and list is shown again
getListView().setSelectionFromTop(index, top);

onBackPressed ()에서 :

// Show the top item at next start of the app
index = 0;
top = 0;

0

여기에 제공된 솔루션 중 어느 것도 나를 위해 작동하지 않는 것 같습니다. 내 경우에는 ListView에서 Fragment교체하는 in이 FragmentTransaction있으므로 Fragment조각이 표시 될 때마다 새 인스턴스가 생성되므로 ListView상태를의 멤버로 저장할 수 없습니다 Fragment.

대신, 나는 커스텀 Application클래스에 상태를 저장했다 . 아래 코드는 이것이 어떻게 작동하는지에 대한 아이디어를 제공해야합니다.

public class MyApplication extends Application {
    public static HashMap<String, Parcelable> parcelableCache = new HashMap<>();


    /* ... code omitted for brevity ... */
}

 

public class MyFragment extends Fragment{
    private ListView mListView = null;
    private MyAdapter mAdapter = null;


    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        mAdapter = new MyAdapter(getActivity(), null, 0);
        mListView = ((ListView) view.findViewById(R.id.myListView));

        Parcelable listViewState = MyApplication.parcelableCache.get("my_listview_state");
        if( listViewState != null )
            mListView.onRestoreInstanceState(listViewState);
    }


    @Override
    public void onPause() {
        MyApplication.parcelableCache.put("my_listview_state", mListView.onSaveInstanceState());
        super.onPause();
    }

    /* ... code omitted for brevity ... */

}

기본 아이디어는 상태를 프래그먼트 인스턴스 외부에 저장하는 것입니다. 응용 프로그램 클래스에 정적 필드가 있다는 아이디어가 마음에 들지 않으면 조각 인터페이스를 구현하고 활동에 상태를 저장하여 할 수 있다고 생각합니다.

또 다른 해결책은에 저장하는 SharedPreferences것이지만 조금 더 복잡해지며 응용 프로그램 실행 중에 상태를 유지하지 않으려면 응용 프로그램을 시작할 때 선택을 취소해야합니다.

 

또한 "첫 번째 항목이 표시 될 때 스크롤 위치가 저장되지 않음"을 피하기 위해 0px높이가 있는 더미 첫 번째 항목을 표시 할 수 있습니다 . 다음 getView()과 같이 어댑터 를 재정의 하면됩니다.

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    if( position == 0 ) {
        View zeroHeightView = new View(parent.getContext());
        zeroHeightView.setLayoutParams(new ViewGroup.LayoutParams(0, 0));
        return zeroHeightView;
    }
    else
        return super.getView(position, convertView, parent);
}

0

내 대답은 Firebase이고 위치 0은 해결 방법입니다.

Parcelable state;

DatabaseReference everybody = db.getReference("Everybody Room List");
    everybody.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            state = listView.onSaveInstanceState(); // Save
            progressBar.setVisibility(View.GONE);
            arrayList.clear();
            for (DataSnapshot messageSnapshot : dataSnapshot.getChildren()) {
                Messages messagesSpacecraft = messageSnapshot.getValue(Messages.class);
                arrayList.add(messagesSpacecraft);
            }
            listView.setAdapter(convertView);
            listView.onRestoreInstanceState(state); // Restore
        }

        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {
        }
    });

그리고 convertView

위치 0 a 사용하지 않는 빈 항목 추가

public class Chat_ConvertView_List_Room extends BaseAdapter {

private ArrayList<Messages> spacecrafts;
private Context context;

@SuppressLint("CommitPrefEdits")
Chat_ConvertView_List_Room(Context context, ArrayList<Messages> spacecrafts) {
    this.context = context;
    this.spacecrafts = spacecrafts;
}

@Override
public int getCount() {
    return spacecrafts.size();
}

@Override
public Object getItem(int position) {
    return spacecrafts.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}

@SuppressLint({"SetTextI18n", "SimpleDateFormat"})
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        convertView = LayoutInflater.from(context).inflate(R.layout.message_model_list_room, parent, false);
    }

    final Messages s = (Messages) this.getItem(position);

    if (position == 0) {
        convertView.getLayoutParams().height = 1; // 0 does not work
    } else {
        convertView.getLayoutParams().height = RelativeLayout.LayoutParams.WRAP_CONTENT;
    }

    return convertView;
}
}

나는 사용자를 방해하지 않고이 작업을 일시적으로 보았습니다.


0

아래 코드를 사용하십시오 :

int index,top;

@Override
protected void onPause() {
    super.onPause();
    index = mList.getFirstVisiblePosition();

    View v = challengeList.getChildAt(0);
    top = (v == null) ? 0 : (v.getTop() - mList.getPaddingTop());
}

데이터를 새로 고칠 때마다 아래 코드를 사용하십시오.

adapter.notifyDataSetChanged();
mList.setSelectionFromTop(index, top);

0

FirebaseListAdapter를 사용 하고 있으며 솔루션을 사용할 수 없습니다. 나는 이것을 끝내었다. 더 우아한 방법이 있다고 생각하지만 이것은 완전하고 효과적인 솔루션입니다.

onCreate 전에 :

private int reset;
private int top;
private int index;

FirebaseListAdapter 내부 :

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

     // Only do this on first change, when starting
     // activity or coming back to it.
     if(reset == 0) {
          mListView.setSelectionFromTop(index, top);
          reset++;
     }

 }

onStart :

@Override
protected void onStart() {
    super.onStart();
    if(adapter != null) {
        adapter.startListening();
        index = 0;
        top = 0;
        // Get position from SharedPrefs
        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
        top = sharedPref.getInt("TOP_POSITION", 0);
        index = sharedPref.getInt("INDEX_POSITION", 0);
        // Set reset to 0 to allow change to last position
        reset = 0;
    }
}

중지 :

@Override
protected void onStop() {
    super.onStop();
    if(adapter != null) {
        adapter.stopListening();
        // Set position
        index = mListView.getFirstVisiblePosition();
        View v = mListView.getChildAt(0);
        top = (v == null) ? 0 : (v.getTop() - mListView.getPaddingTop());
        // Save position to SharedPrefs
        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
        sharedPref.edit().putInt("TOP_POSITION" + "", top).apply();
        sharedPref.edit().putInt("INDEX_POSITION" + "", index).apply();
    }
}

나는 또한 이것을 해결해야했기 때문에 FirebaseRecyclerAdapter 대해서도이 여기에 솔루션을 게시하고 있습니다.

onCreate 전에 :

private int reset;
private int top;
private int index;

FirebaseRecyclerAdapter 내부 :

@Override
public void onDataChanged() {
    // Only do this on first change, when starting
    // activity or coming back to it.
    if(reset == 0) {
        linearLayoutManager.scrollToPositionWithOffset(index, top);
        reset++;
    }
}

onStart :

@Override
protected void onStart() {
    super.onStart();
    if(adapter != null) {
        adapter.startListening();
        index = 0;
        top = 0;
        // Get position from SharedPrefs
        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
        top = sharedPref.getInt("TOP_POSITION", 0);
        index = sharedPref.getInt("INDEX_POSITION", 0);
        // Set reset to 0 to allow change to last position
        reset = 0;
    }
}

중지 :

@Override
protected void onStop() {
    super.onStop();
    if(adapter != null) {
        adapter.stopListening();
        // Set position
        index = linearLayoutManager.findFirstVisibleItemPosition();
        View v = linearLayoutManager.getChildAt(0);
        top = (v == null) ? 0 : (v.getTop() - linearLayoutManager.getPaddingTop());
        // Save position to SharedPrefs
        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
        sharedPref.edit().putInt("TOP_POSITION" + "", top).apply();
        sharedPref.edit().putInt("INDEX_POSITION" + "", index).apply();
    }
}

0

Ryan Newsom 의 탁월한 답변을 명확하게 설명하고 프래그먼트 및 "마스터"ListView 프래그먼트에서 "세부 사항"프래그먼트로 이동 한 다음 "마스터"로 돌아 가려는 일반적인 경우에 맞게 조정합니다.

    private View root;
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
        {
           if(root == null){
             root = inflater.inflate(R.layout.myfragmentid,container,false);
             InitializeView(); 
           } 
           return root; 
        }

    public void InitializeView()
    {
        ListView listView = (ListView)root.findViewById(R.id.listviewid);
        BaseAdapter adapter = CreateAdapter();//Create your adapter here
        listView.setAdpater(adapter);
        //other initialization code
    }

여기서 "마법"은 세부 사항 조각에서 ListView 조각으로 다시 탐색 할 때보기가 다시 작성되지 않고 ListView의 어댑터를 설정하지 않으므로 모든 것이 그대로 유지됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.