Keep / save / restore scroll position when returning to ListView

I have a long ListView where users can scroll before returning to the previous screen. When the user opens this ListView again, I want the list to scroll to the same location as before. Any ideas on how to achieve this?

#1 building

Warning!! If ListView.getFirstVisiblePosition() is 0, there is an error in the AbsListView that does not allow onSaveState() to work properly.

Therefore, if you have a large image that occupies most of the screen and you scroll to the second image, but the first image is displayed, the scroll position will not be saved

From AbsListView.java:1650 (comment on my)

// 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 case, the "top" in the following code will be a negative number, which will cause other problems that prevent the state from recovering properly. So when the top is negative, choose 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);

#2 building

I posted this because I was surprised that no one mentioned it.

When the user clicks the back button, he will return to the list view in the same state as when he exits.

This code will override the "up" button with the same behavior as the back button, so in the case of Listview - > details - > return to Listview (and no other options), this is the simplest code to maintain the scrolling position and content in the list view.

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

Warning: if you can move from a detail activity to another activity, the up button will return to that activity, so you must manipulate the back button history for it to take effect.

#3 building

Is the simple android:saveEnabled="true" android:saveEnabled="true" in the ListView xml declaration sufficient?

#4 building

If you are using clips hosted on an activity, you can do the following:

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

#5 building

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.

Tags: Android Java xml Fragment

Posted on Tue, 11 Feb 2020 04:02:24 -0800 by ragtek