记录和恢复ListView的滑动位置

前言

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

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

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

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

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

记录和恢复ListView的滑动位置_第1张图片

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

你可能感兴趣的:(记录和恢复ListView的滑动位置)