我有一个很长的ListView,用户可以在返回前一个屏幕之前滚动它。当用户再次打开这个ListView时,我希望列表被滚动到与之前相同的位置。关于如何实现这一点,你有什么想法吗?


当前回答

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

这就够了

其他回答

最好的解决方案是:

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

你必须在邮件和线程中调用!

我发布这篇文章是因为我很惊讶没有人提到这一点。

当用户单击返回按钮后,他将返回到列表视图,在相同的状态,因为他离开它。

这段代码将覆盖“向上”按钮的行为与后退按钮相同,所以在Listview ->细节->回到Listview(没有其他选项)的情况下,这是最简单的代码来维护滚动位置和Listview中的内容。

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

注意:如果你可以从细节活动转到另一个活动,向上按钮将返回到该活动,所以你必须操作后退按钮历史,以使其工作。

我使用的是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++;
     }

 }

启动时间:

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

启动时间:

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

试试这个:

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

Explanation: ListView.getFirstVisiblePosition() returns the top visible list item. But this item may be partially scrolled out of view, and if you want to restore the exact scroll position of the list you need to get this offset. So ListView.getChildAt(0) returns the View for the top list item, and then View.getTop() - mList.getPaddingTop() returns its relative offset from the top of the ListView. Then, to restore the ListView's scroll position, we call ListView.setSelectionFromTop() with the index of the item we want and an offset to position its top edge from the top of the ListView.

为了澄清Ryan Newsom的精彩回答并针对片段进行调整通常情况下,我们想要从主ListView片段导航到细节片段然后再返回主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的适配器,所以一切都保持不变!