记录和恢复ListView的滑动位置

作者: ONEWateR | 来源:发表于2015-10-16 20:42 被阅读1985次

前言

有时候我们需要记录和恢复ListView的滑动位置,网上给出大体的解决方案有2种。

  1. 记录上次滑动的坐标,恢复的时候直接scrollTo
  2. 记录listView显示在屏幕上的第一个item的位置,然后利用setSelection恢复

我们分别来探讨一下这两种方案。

1、记录上次滑动的坐标,恢复的时候直接scrollTo

网上的步骤是通过监听ListView的滑动,在他停止滑动时通过listView.getScrollY();获取他的滑动坐标,然后再用scrollTo去恢复。
这样存在的问题是,getScrollY()永远为0,scrollTo会出现后面没有刷新的内容(一片空白)。

2、记录listView显示在屏幕上的第一个item的位置

getFirstVisiblePosition来记录和恢复可以避免方案1的各种问题,但是,他无法精确的恢复原来的位置,只是回滚到以getFirstVisiblePosition的View的起始位置。

我的解决方案

首先一要能精确回滚,二要能避免回滚后出现的一片空白。
所以只能放弃方案2,完善方案1,解决要点在于:

正确获取getScrollY()的滑动坐标

    public int getScrollY() {
        View c = mListView.getChildAt(0);
        if (c == null) {
            return 0;
        }
        int firstVisiblePosition = mListView.getFirstVisiblePosition();
        int top = c.getTop();
        return -top + firstVisiblePosition * c.getHeight() ;
    }

这里的实现思路比较简单,就是计算屏幕显示部分上面的高度,通过获取第一个view(显示的)的top坐标(负数),用这个绝对值加上他之前的高度和就可以算出滑动的y坐标。

正确的回滚

直接scrollTo明显是不行的,他会导致后面有一片空白,而且一滑动ListView会重新刷新一下界面有明显的卡顿。

因此,我们只能使用smoothScrollBy的方法,短时间内平滑移动至记录的位置。
简单的通过smoothScrollBy来恢复明显是不行的,我们需要通过post方法去实现。

        mListView.post(new Runnable() {
            @Override
            public void run() {
                mListView.smoothScrollBy(scrolledY, 0);
            }
        });

这样就可以正确的回滚之前记录的位置。

小结

以上是小弟在解决该问题的一个小小思路,写出来方便大家一起探讨交流。
最后附上代码(比较简陋):


/**
 * 用于记录和恢复ListView的滑动位置
 * Created by ONEWateR on 2015/10/16.
 */
public class ListViewRecord {

    private ListView mListView;

    private int scrolledY;

    public ListViewRecord(ListView listView) {
        mListView = listView;
    }

    /**
     * 设置listView的滑动监听
     */
    public void initEvent() {
        mListView.setOnScrollListener(new AbsListView.OnScrollListener() {

            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                // 不滚动时记录当前滚动到的位置
                if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
                    record();
                }
            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            }
        });
    }

    /**
     * 记录位置
     */
    public void record() {
        scrolledY = getScrollY();
    }

    /**
     * 获取ListView的ScrollY
     * @return
     */
    public int getScrollY() {
        View c = mListView.getChildAt(0);
        if (c == null) {
            return 0;
        }
        int firstVisiblePosition = mListView.getFirstVisiblePosition();
        int top = c.getTop();
        return -top + firstVisiblePosition * c.getHeight() ;
    }

    /**
     * 恢复位置
     */
    public void restore() {
        mListView.post(new Runnable() {
            @Override
            public void run() {
                mListView.smoothScrollBy(scrolledY, 0);
            }
        });
    }

}

使用方法:

初始化

ListViewRecord record = new ListViewRecord(listView);
record.initEvent();

恢复

record.restore();

相关文章

网友评论

  • 9f66d5b90571:这种方法只适用listview只有一页的情况,要是做了分页,在跳到记录的位置时,后面没有数据,就跳不过去了,请问有解决办法吗?
  • 狮_子歌歌:我觉得你计算滑动坐标的方法是理想状态的,如果每一个item高度不一样,可能就不太准确了。
  • 兣甅:重设adapter之后会有闪动的现象,这个问题很蛋疼 :cold_sweat:
    30f0a9768eea:@b77621405175 请问闪动现象解决了吗?
  • 9c8edd576729:牛叉,博客质量很高,感谢分享!

本文标题:记录和恢复ListView的滑动位置

本文链接:https://www.haomeiwen.com/subject/kvkacttx.html