Robotium 5.0.1 源碼解析之滾動原理

    在之前的控件搜索原理解析的文章中提到了,robotium在搜索控件時具有自動滾動的功能,接着就來了解一下其滾動是怎麼實現的。滾動的功能實現在主要在Scroller.java中(吐槽一下,爲什麼Robotium的類名都起的清晰易懂,而代碼裏的變量名則經常文不對題呢??),主要入口是public boolean scroll(int direction, boolean allTheWay),裏面會根據所需滾動的View類型——ListView, ScrollView以及WebView,分別採取三種不同的操作, 本文先了解一下ListView的滾動。

 

          AbsListView的滾動

 

          滾動原理很簡單,直接利用view.setSelection(int positon)(不用擔心會觸發點擊事件,查看ListView或GridView API文檔的說明,其中有這樣一句, If in touch mode, the item will not be selected but it will still be positioned appropriately. )

        不過雖然結果很簡單,但過程還是有些曲折的,接着看public <T extends AbsListView> boolean scrollList(T absListView, int direction, boolean allTheWay) 這個函數,以向下爲例,跟蹤一下滾動流程。

 

Java代碼  收藏代碼
  1.  public <T extends AbsListView> boolean scrollList(T absListView, int direction, boolean allTheWay) {  
  2.    
  3.               if(absListView == null){  
  4.                      return false;  
  5.               }  
  6.    
  7.                
  8.               if (direction == DOWN) {  
  9.                      //向下滾動  
  10.                      if (allTheWay) {  
  11.                             //allTheWay表示直接滾到底  
  12.                             scrollListToLine(absListView, absListView.getCount()-1);  
  13.                             return false;  
  14.                      }  
  15.                       
  16.                      if (absListView.getLastVisiblePosition() >= absListView.getCount()-1) {  
  17.                             //列表已經處在底部  
  18.                             scrollListToLine(absListView, absListView.getLastVisiblePosition());  
  19.                             return false;  
  20.                      }  
  21.    
  22.                       
  23.                      if(absListView.getFirstVisiblePosition() != absListView.getLastVisiblePosition())  
  24.                             //列表的顯示寬度大於1  
  25.                             scrollListToLine(absListView, absListView.getLastVisiblePosition());  
  26.    
  27.                      else  
  28.                             //列表的顯示寬度等於1,則要滾動至FirstVisiblePosition()+1  
  29.                             scrollListToLine(absListView, absListView.getFirstVisiblePosition()+1);  
  30.    
  31.               } else if (direction == UP) {  
  32.                      if (allTheWay || absListView.getFirstVisiblePosition() < 2) {  
  33.                             //allTheWay或列表長度小於2,則直接滾到頂部  
  34.                             scrollListToLine(absListView, 0);  
  35.                             return false;  
  36.                      }  
  37.             //計算列表的顯示寬度  
  38.                      final int lines = absListView.getLastVisiblePosition() - absListView.getFirstVisiblePosition();  
  39.                      //根據寬度計算出該滾動至第幾行  
  40.                      int lineToScrollTo = absListView.getFirstVisiblePosition() - lines;  
  41.    
  42.                       
  43.                      if(lineToScrollTo == absListView.getLastVisiblePosition())  
  44.                             //當顯示寬度爲1時,向上回滾一行即可  
  45.                             lineToScrollTo--;  
  46.    
  47.                      if(lineToScrollTo < 0)  
  48.                             //當上面的隱藏行數小於顯示寬度時,直接滾動至第一行即可  
  49.                             lineToScrollTo = 0;  
  50.    
  51.                      scrollListToLine(absListView, lineToScrollTo);  
  52.               }  
  53.               sleeper.sleep();  
  54.               return true;  
  55. }  
  56.    
  57.        public <T extends AbsListView> void scrollListToLine(final T view, final int line){  
  58.               if(view == null)  
  59.                      Assert.fail("AbsListView is null!");  
  60.    
  61.               final int lineToMoveTo;  
  62.               if(view instanceof GridView)  
  63.                      //如果是GridView的話再+1  
  64.                      //當向下滾動時,如果只滾動至latsVisiblePositon,顯然會重複顯示一個元素,  
  65.                      //而且當postion > GridView.getCount - 1時,調用gridView.setSelection,gridView直接滾動到底部。  
  66.                      lineToMoveTo = line+1;  
  67.               else  
  68.                      lineToMoveTo = line;  
  69.    
  70.               inst.runOnMainSync(new Runnable(){  
  71.                      public void run(){  
  72.                             //通過setSelection完成列表的自動滾動。  
  73.                             view.setSelection(lineToMoveTo);  
  74.                      }  
  75.               });  

 

    對ListView比較瞭解的話,這裏的代碼應該很簡單。不過有一個地方不明白,就是scrollListToLine對GridView的lineToMoveTo加了一。目前經過查看API文檔和自己做得實驗,找到+1的理由只有如下兩點:

1) 當方向向下且列表顯示寬度大於1時,加1可以避免lastVisiblePositon元素的重複顯示

2) 當postion > view.size() – 1時,setSelection(postion) 會導致listView會滾動至頂部,而GridView會滾動至底部。

所以當滾動方向向下且列表寬度超過1時,此GridView的+1是能正常工作的。

 

不過,在如下情況下這個+1應該是會出錯的:

 

1) 當方向向下且列表寬度爲1時,此時在第一層searchFor時已經加了1,而scrollListToLine這裏再給GridView加了1,那麼如果原本的lastVisiblePosition爲26的話,經過這樣處理,會直接滾動到28,而27行就被直接跳過了(經過親自驗證,此時確實會出現問題)。

 

2) 方向向上時,這個+1就更加無厘頭了,例如當用Solo.scrollToTop()時,gridView會滾到position = 1;更例如當列表寬度爲1時,調用Solo.scrollUp(),你會發現gridView在原地踏步(兩條都驗證完畢)。

 

 

 

          ScrollView的滾動

 

    相對比AbsListView,ScrollView的滾動就簡單多了,直接上代碼

Java代碼  收藏代碼
  1. private boolean scrollScrollView(final ScrollView view, int direction){  
  2.   
  3.     if(view == null){  
  4.         return false;  
  5.     }  
  6.     //獲取控件高度  
  7.     int height = view.getHeight();  
  8.     //滾動量減一,爲了容錯性?  
  9.     height--;  
  10.     int scrollTo = -1;  
  11.   
  12.     //向下滾動,滾動量爲正值  
  13.     if (direction == DOWN) {  
  14.         scrollTo = height;  
  15.     }  
  16.     //向下滾動,滾動量爲負  
  17.     else if (direction == UP) {  
  18.         scrollTo = -height;  
  19.     }  
  20.   
  21.     //記錄當前控件處於滾動框頂部的位置  
  22.     int originalY = view.getScrollY();  
  23.     final int scrollAmount = scrollTo;  
  24.     inst.runOnMainSync(new Runnable(){  
  25.         public void run(){  
  26.             //滾動  
  27.             view.scrollBy(0, scrollAmount);  
  28.         }  
  29.     });  
  30.   
  31.     //對比滾動前後的位置,如果一樣,說明已到達底部,返回false,否則返回true  
  32.     if (originalY == view.getScrollY()) {  
  33.         return false;  
  34.     }  
  35.     else{  
  36.         return true;  
  37.     }  
  38. }  

     

    WebView的滾動

 

    更加簡單,不多說了

Java代碼  收藏代碼
  1. public boolean scrollWebView(final WebView webView, int direction, final boolean allTheWay){  
  2.   
  3.     //滾動webView時,直接調用webView.pageDown()或  
  4.     //webView.pageUp()  
  5.     if (direction == DOWN) {  
  6.         inst.runOnMainSync(new Runnable(){  
  7.             public void run(){  
  8.                 canScroll =  webView.pageDown(allTheWay);  
  9.             }  
  10.         });  
  11.     }  
  12.     if(direction == UP){  
  13.         inst.runOnMainSync(new Runnable(){  
  14.             public void run(){  
  15.                 canScroll =  webView.pageUp(allTheWay);  
  16.             }  
  17.         });  
  18.     }  
  19.     return canScroll;  
  20. }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章