ListView获取垂直滚动距离

在开发过程中,可能需要获取ListView的垂直滚动距离,通过滚动距离,来做一些UI上的变化。在ListView的OnScrollListener监听器中,只提供了第一个可见Item的位置(firstVisibleItem)、可见Item的总数(visibleItemCount)以及Item的总数(totalItemCount),并没有提供直接获取垂直滚动距离的方法,这时需要自己通过这些参数来计算ListView垂直滚动距离。

说一下具体实现的思路:
(1)监听ListView的滚动事件,在onScroll方法中,首先将当前第一个可见Item的高度和top存入到SparseArray中。

(2)然后在获取垂直滚动距离时,从SparseArray中取出所有被滑动隐藏的Item的高度相加,即得到了被滑动隐藏掉的Item的高度总和。

(3)最后用高度总和加上当前第一个可见Item的top值,该top值就是当前第一个可见Item被滑动隐藏掉的高度,这样就得到了ListView垂直滚动的距离。具体实现代码如下所示:

mListView.setOnScrollListener(new OnScrollListener() {
    // 创建一个稀疏数组,用于存储Item的高度和mTop
    private SparseArray recordSp = new SparseArray(0);
    private int mCurrentFirstVisibleItem = 0;

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {

    }

    @Override
   public void onScroll(AbsListView view, int firstVisibleItem, 
                         int visibleItemCount, int totalItemCount) {
        mCurrentFirstVisibleItem = firstVisibleItem;
        // 这里获取的Item是ListView中第一个可见的Item
        View firstView = view.getChildAt(0);
        if (null != firstView) {
            ItemRecord itemRecord = 
                    (ItemRecord) recordSp.get(firstVisibleItem);
            if (null == itemRecord) {
                itemRecord = new ItemRecord();
            }
            itemRecord.height = firstView.getHeight();
            // top值总是小于或等于0的
            itemRecord.top = firstView.getTop();
            /**
            * 将当前第一个可见Item的高度和top存入SparseArray中,
            * SparseArray的key是Item的position
            */
            recordSp.append(firstVisibleItem, itemRecord);
            int scrollY = getScrollY();
            Log.i(TAG, "垂直滚动距离:" + scrollY);
        }

    }

    private int getScrollY() {
        int height = 0;
        for (int i = 0; i < mCurrentFirstVisibleItem; i++) {
            /**
             * 取出所有已滑过的Item的高度,相加。
             * 说明下这里为什么不直接用一个Item高度乘以所有已滑过的Item的数量,
             * 主要是考虑到可能为ListView添加Header这种情况,如果Header的高度
             * 与Item的高度是相同的可以这样做,如果Header的高度不等于Item的高度,
             * 这时将Header的高度直接按照Item的高度来计算就不准确了。
             */
            ItemRecord itemRecord = (ItemRecord) recordSp.get(i);
            height += itemRecord.height;
        }
        //取出当前第一个可见Item的ItemRecord对象
        ItemRecord itemRecord = 
                (ItemRecord) recordSp.get(mCurrentFirstVisibleItem);
        if (null == itemRecord) {
            itemRecord = new ItemRecord();
        }
        //由于存入的top值是小于或等于0的,这里是减去top值而不是加
        return height - itemRecord.top;
    }

    class ItemRecord {
        int height = 0;
        int top = 0;
    }
});

推荐阅读更多精彩内容