在方向更改时恢复列表视图中的项目和滚动位置

Posted

技术标签:

【中文标题】在方向更改时恢复列表视图中的项目和滚动位置【英文标题】:Restore items and scroll position in listview on orientation change 【发布时间】:2020-10-07 19:50:07 【问题描述】:

我尝试通过多种方式在用户旋转手机时恢复列表视图的数据。但是,由于我转动屏幕一次,它可以工作,但是当我转动它时,我遇到了一些困难再过一段时间,它就不再起作用了。另外,我尝试恢复滚动位置但没有成功。

所以我想知道最好的方法。


我的代码:

private ListView item_container;
private ArrayList<Song.Hits> values;

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    item_container = findViewById(R.id.bottom_popup_container);

当我完成从 API 检索数据时,我将它们加载到列表视图中(并保存数据):

@Override
public void onRequestFinish(ArrayList<Song.Hits> hits) 
    if (!hits.isEmpty()) 
        CAdapter adapter = new CAdapter(hits);
        item_container.setAdapter(adapter);
        values = adapter.getHits();
    ;

最后,我重写了这2个方法来保存listview的位置和item。

    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) 
        outState.putParcelableArrayList("list",  values);
        outState.putParcelable("pos", item_container.onSaveInstanceState());
        super.onSaveInstanceState(outState);
    

    @Override
    protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) 
        super.onRestoreInstanceState(savedInstanceState);
            ArrayList<Song.Hits> values = savedInstanceState.getParcelableArrayList("list");
            if (values != null) 
                CAdapter adapter = new CAdapter(values);
                item_container.setAdapter(adapter);
                item_container.onRestoreInstanceState(savedInstanceState.getParcelable("pos"));
            
    

【问题讨论】:

【参考方案1】:

在不相关的程度上,您可能应该使用RecyclerView 而不是ListView,后者现在还支持自定义状态恢复策略,以便在设置数据之前自动保留滚动状态。

无论如何,按照当前的方法,应该像

@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) 
    super.onRestoreInstanceState(savedInstanceState);
    ArrayList<Song.Hits> values = savedInstanceState.getParcelableArrayList("list");

应该是

@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) 
    super.onRestoreInstanceState(savedInstanceState);
    values = savedInstanceState.getParcelableArrayList("list");

【讨论】:

【参考方案2】:

您还应该更新 OnCreate 方法或覆盖 OnPostCreate 方法,并在检查是否 savedInstanceState!=null 时添加您在 onRestoreInstanceState 中使用的逻辑

【讨论】:

它第一次工作,但是当我第二次旋转我的手机时,列表视图消失了【参考方案3】:

您应该对onCreate 进行相同的检查,因为onRestoreInstanceState 并不总是被调用,这有点棘手。

您可以从文档中查看:

该方法在活动进行时在onStart()之后调用 从先前保存的状态重新初始化,在此处给出 savedInstanceState。大多数实现将简单地使用 onCreate(Bundle) 恢复他们的状态,但有时是 完成所有初始化后,方便在这里进行 或允许子类决定是否使用您的默认值 执行。此方法的默认实现执行 恢复以前被冻结的任何视图状态 onSaveInstanceState(Bundle).

将您的逻辑移至onCreate,您会没事的

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    item_container = findViewById(R.id.bottom_popup_container);

    if (savedInstanceState != null) 
        ArrayList<Song.Hits> values = savedInstanceState.getParcelableArrayList("list");
        if (values != null) 
            CAdapter adapter = new CAdapter(values);
            item_container.setAdapter(adapter);
                item_container.onRestoreInstanceState(savedInstanceState.getParcelable("pos"));
        
    

【讨论】:

同样的行为仍然存在,第一次运行良好,但是当我再次旋转手机时,列表视图消失了..

以上是关于在方向更改时恢复列表视图中的项目和滚动位置的主要内容,如果未能解决你的问题,请参考以下文章

更改视图控制器时保持滚动位置

Imageview 在滚动列表视图上自动更改

列表视图滚动更改项目视图的背景颜色(简单适配器)

当视图当前不可见时更改集合视图的滚动位置

在视图之间导航时更改表视图的位置

当 ipad 中的方向发生两次变化时,UIScrollView 的位置会发生变化