ListView的滑动监听,是ListView中最重要的技巧,很多重写的ListView,基本上都是在滑动事件的处理上下功夫,通过判断滑动事件进行不同的逻辑处理。而为了更加精确的监听滑动事件,通常还需要使用GestureDetector手势识别、VelocityTracker滑动速度监测等辅助类来完成更好的监听。下面我们来介绍两种监听ListView滑动事件的方法。

1、OnTouchListener

OnTouchListener是view中的监听事件,通过监听ACTION_DOWN 、ACTION_MOVE、 ACTION_UP这三个事件发生时的坐标,就可以根据坐标判断用户滑动的方向,并在不同的事件中进行相应的逻辑处理,这种方式的使用代码如下:

listView.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            //触摸时操作
            case MotionEvent.ACTION_DOWN:
                break;
            //移动时操作
            case MotionEvent.ACTION_MOVE:
                break;
            //离开时操作
            case MotionEvent.ACTION_UP:
                break;
        }
        return false;
    }
});

2、OnScrollListener

OnScrollListener是AbsListView中的监听事件,它封装了很多与Listview相关的信息,使用起来也更加灵活。首先来看一下OnScrollListener的一般使用方法,代码如下:

listView.setOnScrollListener(new OnScrollListener() {
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        switch (scrollState) {
            //滑动停止时
            case OnScrollListener.SCROLL_STATE_IDLE:
                break;
            //正在滚动
            case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
                break;
            //手指抛动时,即手指用力滑动,在离开后listview由于惯性继续滑动的状态
            case OnScrollListener.SCROLL_STATE_FLING:
                break;
        }
    }
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        //滑动时一直调用
    }
});

当用户没有做手指抛动的状态时,OnScrollStateChanged()这个方法只会回调2次,否则会回调3次,差别就是手指抛动的这个状态。通常情况下,我们会在这个方法中通过不同的状态来设置一些标志flag,来区分不同的滑动状态,供其他方法处理。

onScroll()这个回调方法,它在ListView滚动时会一直回调,而方法中的后三个int类型的参数,则非常精确地显示了当前ListView滚动状态,这单个参数如下所示:

firstVisibleItem当前能看见的第一个item的id(从0开始)

visibleItemCount当前能看见的item总数

totalItemCount整个ListView的item总数

这里需要注意的是,当前能看见的item数,包括没有显示完整的item,即显示一小半的item也包括在内了。通过这几个参数可以很方便的进行一些判断,比如判断是否滚动到最后一行,就可以使用如下代码进行判断:

if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount >0){
    //滚动到最后一行
}

再比如,可以通过如下代码判断滚动的方向,代码如下所示:

if (firstVisibleItem > lastVisibleItemPosition) {
    //上滑
} else if (firstVisibleItem < lastVisibleItemPosition) {
    //下滑
}

通过一个成员变量lastVisibleItemPosition来记录上次第一个可视的item的id并与当前可视item的id进行比较,即可知道当前滚动方向。

ListView也给我们提供了一些封装的方法来获得当前可视的item的位置等信息

//获取可视区域内最后一个item的id
listView.getLastVisiblePosition();
//获取可视区域内第一个item的id
listView.getFirstVisiblePosition();