OnScrollListener詳解

官方文檔:http://developer.android.com/ref ... ScrollListener.html

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, int totalItemCount) { 

   }

});

監聽ListView滾動到最底部使用 onScrollStateChanged(AbsListView view, int scrollState) 方法,代碼大致如下:
// 監聽listview滾到最底部

mIndexList.setOnScrollListener(new OnScrollListener() {  

  @Override  

  public void onScrollStateChanged(AbsListView view, int scrollState) {    

    switch (scrollState) {            // 當不滾動時     

       case OnScrollListener.SCROLL_STATE_IDLE:                // 判斷滾動到底部            

    if (view.getLastVisiblePosition() == (view.getCount() - 1)) { 

                   isLastisNext++;            

  }           

   break;   

     }  

  }   

  @Override    public void onScroll(AbsListView view, int firstVisibleItem,           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。這個是不確定的。有待考證。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章