Maintain/Save/Restore scroll position when returning to a ListView

后端 未结 20 1651
無奈伤痛
無奈伤痛 2020-11-21 21:30

I have a long ListView that the user can scroll around before returning to the previous screen. When the user opens this ListView again, I want the

相关标签:
20条回答
  • 2020-11-21 22:05

    To clarify the excellent answer of Ryan Newsom and to adjust it for fragments and for the usual case that we want to navigate from a "master" ListView fragment to a "details" fragment and then back to the "master"

        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
        }
    

    The "magic" here is that when we navigate back from the details fragment to the ListView fragment, the view is not recreated, we don't set the ListView's adapter, so everything stays as we left it!

    0 讨论(0)
  • 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

    0 讨论(0)
  • 2020-11-21 22:08

    Am posting this because I am surprised nobody had mentioned this.

    After user clicks the back button he will return to the listview in the same state as he went out of it.

    This code will override the "up" button to behave the same way as the back button so in the case of Listview -> Details -> Back to Listview (and no other options) this is the simplest code to maintain the scrollposition and the content in the listview.

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

    Caution: If you can go to another activity from the details activity the up button will return you back to that activity so you will have to manipulate the backbutton history in order for this to work.

    0 讨论(0)
  • 2020-11-21 22:08

    BEST SOLUTION IS:

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

    YOU MUST CALL IN POST AND IN THREAD!

    0 讨论(0)
  • 2020-11-21 22:09
    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);
        }
    }
    
    0 讨论(0)
  • 2020-11-21 22:09

    If you are saving/restoring scroll position of ListView yourself you are essentially duplicating the functionality already implemented in android framework. The ListView restores fine scroll position just well on its own except one caveat: as @aaronvargas mentioned there is a bug in AbsListView that won't let to restore fine scroll position for the first list item. Nevertheless the best way to restore scroll position is not to restore it. Android framework will do it better for you. Just make sure you have met the following conditions:

    • make sure you have not called setSaveEnabled(false) method and not set android:saveEnabled="false" attribute for the list in the xml layout file
    • for ExpandableListView override long getCombinedChildId(long groupId, long childId) method so that it returns positive long number (default implementation in class BaseExpandableListAdapter returns negative number). Here are examples:

    .

    @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;
    }
    
    • if ListView or ExpandableListView is used in a fragment do not recreate the fragment on activity recreation (after screen rotation for example). Obtain the fragment with findFragmentByTag(String tag) method.
    • make sure the ListView has an android:id and it is unique.

    To avoid aforementioned caveat with first list item you can craft your adapter the way it returns special dummy zero pixels height view for the ListView at position 0. Here is the simple example project shows ListView and ExpandableListView restore their fine scroll positions whereas their scroll positions are not explicitly saved/restored. Fine scroll position is restored perfectly even for the complex scenarios with temporary switching to some other application, double screen rotation and switching back to the test application. Please note, if you are explicitly exiting the application (by pressing the Back button) the scroll position won't be saved (as well as all other Views won't save their state). https://github.com/voromto/RestoreScrollPosition/releases

    0 讨论(0)
提交回复
热议问题