记录和恢复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