OnScrollListener


SCROLL_STATE_FLING是指手指快速拖动后,手指离开,页面惯性滑动的状态。


ListView之滚动事件--OnScrollListener


onScrollStateChanged ( AbsListView  view, int scrollState) 中,scrollState有三种状态,分别是开始滚动( SCROLL_STATE_FLING ),正在滚动( SCROLL_STATE_TOUCH_SCROLL ), 已经停止( SCROLL_STATE_IDLE ),对于滚动事件的处理,很有必要知道。


ListView继承自AbsListView
AbsListView中有一个滚动事件的Listenter,如下:
    public interface OnScrollListener {

        /**
         * The view is not scrolling. Note navigating the list using the trackball counts as
         * being in the idle state since these transitions are not animated.
         */
        public static int SCROLL_STATE_IDLE = 0;

        /**
         * The user is scrolling using touch, and their finger is still on the screen
         */
        public static int SCROLL_STATE_TOUCH_SCROLL = 1;

        /**
         * The user had previously been scrolling using touch and had performed a fling. The
         * animation is now coasting to a stop
         */
        public static int SCROLL_STATE_FLING = 2;

        /**
         * Callback method to be invoked while the list view or grid view is being scrolled. If the
         * view is being scrolled, this method will be called before the next frame of the scroll is
         * rendered. In particular, it will be called before any calls to
         * {@link Adapter#getView(int, View, ViewGroup)}.
         *
         * @param view The view whose scroll state is being reported
         *
         * @param scrollState The current scroll state. One of {@link #SCROLL_STATE_IDLE},
         * {@link #SCROLL_STATE_TOUCH_SCROLL} or {@link #SCROLL_STATE_IDLE}.
         */
        public void onScrollStateChanged(AbsListView view, int scrollState);

        /**
         * Callback method to be invoked when the list or grid has been scrolled. This will be
         * called after the scroll has completed
         * @param view The view whose scroll state is being reported
         * @param firstVisibleItem the index of the first visible cell (ignore if
         *        visibleItemCount == 0)
         * @param visibleItemCount the number of visible cells
         * @param totalItemCount the number of items in the list adaptor
         */
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
                int totalItemCount);
    }

****************************************************************************************************************************************
   private boolean mBusy=false; //滚动中
    private OnScrollListener mOnScrollListener = new OnScrollListener(){               
        @Override    
        public void onScrollStateChanged(AbsListView view, int scrollState) {    
             switch (scrollState) {
                case OnScrollListener.SCROLL_STATE_IDLE:
                    mBusy = false;
                    break;
                case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
                    mBusy = true;
                    break;
                case OnScrollListener.SCROLL_STATE_FLING:
                    mBusy = true;
                    break;
             }
        }
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem,
                int visibleItemCount, int totalItemCount) {
            // TODO Auto-generated method stub            
        }       
    };
****************************************************
OnScrollListener还可以方便的实现动态加载数据。
遇到问题要多思考。多动脑,少动手~~!




import java.util.ArrayList;import java.util.List;import  android .app.Activity;import android.os.Bundle;import android.widget.AbsListView;import android.widget.ArrayAdapter;import android.widget.ListAdapter;import android.widget.ListView;import android.widget.AbsListView.OnScrollListener;public class ListViewActivity extends Activity {        private ListView lv;        private List<String> list;        private int lastItem;        private int listSize;        private ListAdapter adapter;    /** Called when the activity is first created. */    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        lv = (ListView) findViewById(R.id.lv);        adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, getData());        lv.setAdapter(adapter);        lv.setOnScrollListener(new OnScrollListener() {                                                @Override                        public void onScrollStateChanged(AbsListView paramAbsListView, int paramInt) {                                //当屏幕停止滚动时为0;当屏幕滚动且用户使用的触碰或手指还在屏幕上时为1;                                //由于用户的操作,屏幕产生惯性滑动时为2                                System.out.println("***lastItem:"+lastItem);                                System.out.println("***listSize:"+listSize);                                if(lastItem == listSize){                                        System.out.println("**************");                                        //数据全部显示出来时运行此处代码,如果要实现分页功能,在这里加载下一页的数据                                }                                                        }                                                @Override                        public void onScroll(AbsListView paramAbsListView, int firstVisibleItem,                                        int visibleItemCount, int totalItemCount) {//                                //        firstVisibleItem表示在现时屏幕第一个ListItem(部分显示的ListItem也算)//                                //        在整个ListView的位置(下标从0开始) //                                System.out.println("***firstParamInt:"+firstVisibleItem);//                                //        visibleItemCount表示在现时屏幕可以见到的ListItem(部分显示的ListItem也算)总数//                                System.out.println("***visibleItemCount:"+visibleItemCount);//                                //        totalItemCount表示ListView的ListItem总数//                                System.out.println("***totalItemCount:"+totalItemCount);                                //        listView.getLastVisiblePosition()表示在现时屏幕最后一个ListItem(最后ListItem要完全                                //        显示出来才算)在整个ListView的位置(下标从0开始)//                                System.out.println("****"+String.valueOf(lv.getLastVisiblePosition()));                                lastItem = lv.getLastVisiblePosition();                        }                });    }    private List<String> getData(){            int i;            list = new ArrayList<String>();            for(i=1; i<10; i++){                    list.add("ListView"+i);            }            listSize = list.size()-1;            return list;    }} 如果还有什么不懂的,见意去看下源码。
              
  

OnScrollListener回调分析




如果adapter中的数据量很大的时候,在加载listview时会出现卡顿的现象。这是会让用户抓狂!最好的解决办法就是先加载一定数量的数据,然后在最下方提示正在加载! 
动态加载就是把放入adapter中的数据分好几次加载。在用户拖动listview时再加载一定的数据,和sina微博的客户端类似。 
给listview添加OnScrollListener监听事件默认会覆盖下面两个方法: 

Java代码

  • 1.new OnScrollListener() {
  • 2.    boolean isLastRow = false;
  • 3.
  • 4.    @Override
  • 5.    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
  • 6.        //滚动时一直回调,直到停止滚动时才停止回调。单击时回调一次。
  • 7.        //firstVisibleItem:当前能看见的第一个列表项ID(从0开始)
  • 8.        //visibleItemCount:当前能看见的列表项个数(小半个也算)
  • 9.        //totalItemCount:列表项共数
  • 10.
  • 11.        //判断是否滚到最后一行
  • 12.        if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) {
  • 13.            isLastRow = true;
  • 14.        }
  • 15.    }
  • 16.    @Override
  • 17.    public void onScrollStateChanged(AbsListView view, int scrollState) {
  • 18.        //正在滚动时回调,回调2-3次,手指没抛则回调2次。scrollState = 2的这次不回调
  • 19.        //回调顺序如下
  • 20.        //第1次:scrollState = SCROLL_STATE_TOUCH_SCROLL(1) 正在滚动
  • 21.        //第2次:scrollState = SCROLL_STATE_FLING(2) 手指做了抛的动作(手指离开屏幕前,用力滑了一下)
  • 22.        //第3次:scrollState = SCROLL_STATE_IDLE(0) 停止滚动
  • 23.
  • 24.        //当滚到最后一行且停止滚动时,执行加载
  • 25.        if (isLastRow && scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
  • 26.            //加载元素
  • 27.            ......
  • 28.
  • 29.            isLastRow = false;
  • 30.        }
  • 31.    }
  • 32.}



一片国外的翻译文档,但是不是很正确
[url=]onScrollListener实施检测在ListView滚动年底[/url]       
    我ListView ListView显示一些项目。我想执行一些当前显示中的可见部分的项目ListView ListView,如何ListView中一直滚动,因此我认为OnScrollListener ListView ListView的。因此到 Android  API参考,onScroll法“将被称为滚动后已经完成”。这在我看来,我需要的东西,因为一旦滚动完成后,我在执行我的行动ListView (onScroll方法返回显示的第一项指数和显示的项目数)。 
但是,一旦实施,我看到LogCat LogCat onScroll方法,不只是发射一次滚动已完成,但发射进入显示视图为每一个新项目,从开始到结束滚动。这不是我所期望的行为,也没有我需要的。 ,而不是其他的侦听器的方法(onScrollStateChanged)不提供有关在当前显示的项目的ListView ListView 。 
所以,没有人知道如何使用这两个方法来检测滚动的结束,并得到所显示的项目信息?之间的API参考资料和实际行为的方法不对,弄得我有点。预先感谢。 
PS:我已经看到了一些类似的主题周围,但没有帮助我了解整个事情的作品..! 

  
  
   [url=]回答[/url]        [url=]1[/url]     为了获得这一行为向下是棘手的,我花了相当长一段时间来完善。肉的问题是,自己的滚动听众是不是真的很足以探测到一个“滚动停止”(包括方向键/轨迹球),至于我可以告诉。我结束了作品的权利,我希望它做的事情结合。 
我想我能做到这一点的最好办法是延长ListView和覆盖的几种方法: 
.... @Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN || keyCode == KeyEvent.KEYCODE_DPAD_UP) { startWait(); } return super.onKeyUp(keyCode, event); } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { stopWait(); } if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { startWait(); } return super.onTouchEvent(event); } private OnScrollListener customScrollListener = new OnScrollListener() { @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { stopWait(); } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if (scrollState =其他= OnScrollListener.SCROLL_STATE_IDLE){startWait();} {stopWait();}}} / /所有这个等待可能得到改善,但是这想法私人主题waitThread = NULL;私人诠释waitCount = Integer.MIN_VALUE的;公共无效stopWait(){waitCount = Integer.MIN_VALUE的;}市民同步无效startWait(){waitCount = 0;(waitThread = NULL){;} waitThread =新主题(新的Runnable(){@覆盖公共无效的run() {尝试{(; waitCount.get()<10; waitCount + +){Thread.sleep代码(50);} / /踢它返回到UI线程view.post(theRunnableWithYourOnScrollStopCode); / /这里是你办什么你想要做关于停止}赶上(InterruptedException E){} {waitThread = NULL;}}}); waitThread.start();}请注意,您还可以customScrollListener customScrollListener在你的构造。这种实现是不错的,我觉得,因为它不会立即火“事件”,它会稍等一会,直到它实际上已经完全停止滚动。 

      
       [url=]2[/url]     在年底,我已经达到了一个解决方案,没有那么多优雅的,但为我工作;想通了,onScroll方法是所谓的每一步的滚动,而不是仅仅在滚动结束,和,onScrollStateChanged实际上是被称为只有当滚动完成后,我这样做: 
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { this.currentFirstVisibleItem = firstVisibleItem; this.currentVisibleItemCount = visibleItemCount; } public void onScrollStateChanged(AbsListView view, int scrollState) { this.currentScrollState = scrollState; this.isScrollCompleted(); } private void isScrollCompleted() { if (this.currentVisibleItemCount > 0 && this.currentScrollState == SCROLL_STATE_IDLE) { /*** In this way I detect if there's been a scroll which has completed ***/ /*** do the work! ***/ } } *** / public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { this.currentFirstVisibleItem = firstVisibleItem; this.currentVisibleItemCount = visibleItemCount; } public void onScrollStateChanged(AbsListView view, int scrollState) { this.currentScrollState = scrollState; this.isScrollCompleted(); } private void isScrollCompleted() { if (this.currentVisibleItemCount > 0 && this.currentScrollState == SCROLL_STATE_IDLE) { /*** In this way I detect if there's been a scroll which has completed ***/ /*** do the work! ***/ } }实际上,每次的ListView的滚动我保存了有关的第一个可见的项目数据,并在可见的项目数(onScroll方法);时,滚动变化的状态(onScrollStateChanged)我保存的状态和我调用另一个方法,这实际上是了解是否有一个滚动的,如果它的完成。这样,我也有可见项目,我需要的数据。也许不干净,但作品! 
关于

      
        
    如果adapter中的数据量很大的时候,在加载listview时会出现卡顿的现象。这是会让用户抓狂!最好的解决办法就是先加载一定数量的数据,然后在最下方提示正在加载!  动态加载就是把放入adapter中的数据分好几次加载。在用户拖动listview时再加载一定的数据,和sina微博的客户端类似。
  给listview添加OnScrollListener监听事件默认会覆盖下面两个方法:
  Java代码 收藏代码
  OnScrollListener loadListener=new OnScrollListener() {
  @Override
  public void onScroll(AbsListView view, int firstVisibleItem,
  int visibleItemCount, int totalItemCount) {
  lastItem = firstVisibleItem + visibleItemCount;
  }
  @Override
  public void onScrollStateChanged(AbsListView view, int scrollState) {
  //listview滚动时会执行这个方法,这儿调用加载数据的方法。
  adapter.notifyDataSetChanged();//提醒adapter更新
  uList.setSelection(lastItem - 1);//设置listview的当前位置,如果不设置每次加载完后都会返回到list的第一项。
  }
  }
  };
  TIP:
  1、如果activity中只有listview,当listview的数据量很大时,在启动activity时会卡顿半天知道数据加载完可以显示,这时可以可以用handler,将加载数据的操作写在handler里面,而且要在onResume()方法中执行,放在onCreate()不起作用。
  2、如果是从网络获取数据,或者数据量很大可以新开一个线程,在线程中完成数据的加载。
  3、如果添加的加载提示框出不来,可能是加载过程一直占有cpu,无法显示提示框,可以将加载的代码写到handler里面,用postDelayed()方法给一定的时间延迟去加载数据。




监听ListView滚动到最底部
                                
监听ListView的滚动可以用两个东西:
  • ListView.onScrollStateChanged (本文讲解这个listener的使用)
  • 在OnGestureListener类里面的onScroll(MotionEvent e1, MotionEvent e2,
                    float distanceX, float distanceY)   事件
SDK的Sample里面的ApiDemos里面的List9 和 List 13介绍了 ListView.OnScrollListener的使用。
List9介绍的是ListView.OnScrollListener的 onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) 方法。
List13介绍的是ListView.OnScrollListener的 onScrollStateChanged(AbsListView view, int scrollState) 方法,使用说明如下:
ListView.setOnScrollListener(new OnScrollListener() {    @Override    public void onScrollStateChanged(AbsListView view, int scrollState) {        switch (scrollState) {            case OnScrollListener.SCROLL_STATE_IDLE:                Log.v("已经停止:SCROLL_STATE_IDLE");                break;            case OnScrollListener.SCROLL_STATE_FLING:                Log.v("开始滚动:SCROLL_STATE_FLING");               break;            case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:   Log.v("正在滚动:SCROLL_STATE_TOUCH_SCROLL");               break;            }    }     @Override    public void onScroll(AbsListView view, int firstVisibleItem,           int visibleItemCount, inttotalItemCount) {    }});

监听ListView滚动到最底部使用 onScrollStateChanged(AbsListView view, int scrollState) 方法,代码大致如下:
// 监听listview滚到最底部mIndexList.setOnScrollListener(new OnScrollListener() {    @Override    public voidonScrollStateChanged(AbsListView view, int scrollState) {        switch (scrollState) {            // 当不滚动时            caseOnScrollListener.SCROLL_STATE_IDLE:                // 判断滚动到底部                if (view.getLastVisiblePosition() == (view.getCount() - 1)) {                    isLastisNext++;              }              break;        }    }     @Override    public void onScroll(AbsListView view, intfirstVisibleItem,           int visibleItemCount, int totalItemCount) {    }});


我使用这个发现两个问题:
  • 在模拟器上,如果使用鼠标的滚轮来滚动时执行 onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)  方法,不执行 onScrollStateChanged(AbsListView view, int scrollState)  方法。只有触摸往下滑动时,才执行onScrollStateChanged(AbsListView view, int scrollState) 方法。有待考证。
  • SCROLL_STATE_TOUCH_SCROLL一定执行,然后下面可能执行SCROLL_STATE_FLING,也可能执行SCROLL_STATE_IDLE。这个是不确定的。有待考证


  1. package com.action;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import android.app.Activity;  
  7. import android.os.Bundle;  
  8. import android.widget.AbsListView;  
  9. import android.widget.ArrayAdapter;  
  10. import android.widget.ListAdapter;  
  11. import android.widget.ListView;  
  12. import android.widget.AbsListView.OnScrollListener;  
  13.   
  14. public class ListViewActivity extends Activity {  
  15.     private ListView lv;  
  16.     private List<String> list;  
  17.     private int lastItem;  
  18.     private int listSize;  
  19.     private ListAdapter adapter;  
  20.     /** Called when the activity is first created. */  
  21.     @Override  
  22.     public void onCreate(Bundle savedInstanceState) {  
  23.         super.onCreate(savedInstanceState);  
  24.         setContentView(R.layout.main);  
  25.         lv = (ListView) findViewById(R.id.lv);  
  26.         adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, getData());  
  27.         lv.setAdapter(adapter);  
  28.         lv.setOnScrollListener(new OnScrollListener() {  
  29.               
  30.             @Override  
  31.             public void onScrollStateChanged(AbsListView paramAbsListView, int paramInt) {  
  32.                 //当屏幕停止滚动时为0;当屏幕滚动且用户使用的触碰或手指还在屏幕上时为1;  
  33.                 //由于用户的操作,屏幕产生惯性滑动时为2  
  34.                 System.out.println("***lastItem:"+lastItem);  
  35.                 System.out.println("***listSize:"+listSize);  
  36.                 if(lastItem == listSize){  
  37.                     System.out.println("**************");  
  38.                     //数据全部显示出来时运行此处代码,如果要实现分页功能,在这里加载下一页的数据  
  39.                 }  
  40.                   
  41.             }  
  42.               
  43.             @Override  
  44.             public void onScroll(AbsListView paramAbsListView, int firstVisibleItem,  
  45.                     int visibleItemCount, int totalItemCount) {  
  46. //              //  firstVisibleItem表示在现时屏幕第一个ListItem(部分显示的ListItem也算)  
  47. //              //  在整个ListView的位置(下标从0开始)   
  48. //              System.out.println("***firstParamInt:"+firstVisibleItem);  
  49. //              //  visibleItemCount表示在现时屏幕可以见到的ListItem(部分显示的ListItem也算)总数  
  50. //              System.out.println("***visibleItemCount:"+visibleItemCount);  
  51. //              //  totalItemCount表示ListView的ListItem总数  
  52. //              System.out.println("***totalItemCount:"+totalItemCount);  
  53.                 //  listView.getLastVisiblePosition()表示在现时屏幕最后一个ListItem(最后ListItem要完全  
  54.                 //  显示出来才算)在整个ListView的位置(下标从0开始)  
  55. //              System.out.println("****"+String.valueOf(lv.getLastVisiblePosition()));  
  56.                 lastItem = lv.getLastVisiblePosition();  
  57.             }  
  58.         });  
  59.     }  
  60.     private List<String> getData(){  
  61.         int i;  
  62.         list = new ArrayList<String>();  
  63.         for(i=1; i<10; i++){  
  64.             list.add("ListView"+i);  
  65.         }  
  66.         listSize = list.size()-1;  
  67.         return list;  
  68.     }  
  69. }  



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值