1. 程式人生 > >View.ViewTreeObserver介紹

View.ViewTreeObserver介紹

複製程式碼
 1  /**註冊一個回撥函式,當在一個檢視樹中的焦點狀態發生改變時呼叫這個回撥函式。
 2   * 引數 listener    將要被新增的回撥函式
 3   *異常 IllegalStateException       如果isAlive() 返回false
 4   */
 5  public void addOnGlobalFocusChangeListener (ViewTreeObserver.OnGlobalFocusChangeListener listener)
 6      
 7  
 8  /**註冊一個回撥函式,當在一個檢視樹中全域性佈局發生改變或者檢視樹中的某個檢視的可視狀態發生改變時呼叫這個回撥函式。
9   *引數 listener 將要被新增的回撥函式 10   *異常 IllegalStateException 如果isAlive() 返回false 11   */ 12  public void addOnGlobalLayoutListener (ViewTreeObserver.OnGlobalLayoutListener listener) 13    14 15    16  /**註冊一個回撥函式,當一個檢視樹將要繪製時呼叫這個回撥函式。 17   *引數 listener 將要被新增的回撥函式 18   *異常 IllegalStateException 如果isAlive() 返回false
19   */ 20  public void addOnPreDrawListener (ViewTreeObserver.OnPreDrawListener listener) 21 22   23  /**註冊一個回撥函式,當一個檢視發生滾動時呼叫這個回撥函式。 24   *引數 listener 將要被新增的回撥函式 25   *異常 IllegalStateException 如果isAlive() 返回false 26   */ 27  public void addOnScrollChangedListener (ViewTreeObserver.OnScrollChangedListener listener)
28 29   30  /**註冊一個回撥函式,當一個觸控模式發生改變時呼叫這個回撥函式。 31   *引數 listener 將要被新增的回撥函式 32   *異常 IllegalStateException 如果isAlive() 返回false 33   */ 34  public void addOnTouchModeChangeListener (ViewTreeObserver.OnTouchModeChangeListener listener) 35 36    37  //當整個佈局發生改變時通知相應的註冊監聽器。如果你強制對檢視佈局或者在一個沒有附加到一個視窗的檢視的層次結構或者在GONE狀態下,它可以被手動的呼叫 38  public final void dispatchOnGlobalLayout () 39 40  /**當一個檢視樹將要繪製時通知相應的註冊監聽器。如果這個監聽器返回true,則這個繪製將被取消並重新計劃。如果你強制對檢視佈局或者在一個沒有附加到一個視窗的檢視的層次結構或者在一個GONE狀態下,它可以被手動的呼叫 41   *返回值 當前繪製能夠取消並重新計劃則返回true,否則返回false。 42   */ 43  public final boolean dispatchOnPreDraw () 44 45  /**指示當前的ViewTreeObserver是否可用(alive)。當observer不可用時,任何方法的呼叫(除了這個方法)都將丟擲一個異常。如果一個應用程式保持和ViewTreeObserver一個歷時較長的引用,它應該總是需要在呼叫別的方法之前去檢測這個方法的返回值。 46   *返回值 但這個物件可用則返回true,否則返回false 47   */ 48  public boolean isAlive () 49 50 51  /**移除之前已經註冊的全域性佈局回撥函式。 52   *引數 victim 將要被移除的回撥函式 53   *異常 IllegalStateException 如果isAlive() 返回false 54   */ 55  public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim) 56    57  /**移除之前已經註冊的焦點改變回調函式。 58   *引數 victim 將要被移除的回撥函式 59   *異常 IllegalStateException 如果isAlive() 返回false 60   */ 61  public void removeOnGlobalFocusChangeListener (ViewTreeObserver.OnGlobalFocusChangeListener victim) 62    63  /**移除之前已經註冊的預繪製回撥函式。 64   *引數 victim 將要被移除的回撥函式 65   *異常 IllegalStateException 如果isAlive() 返回false 66   */ 67  public void removeOnPreDrawListener (ViewTreeObserver.OnPreDrawListener victim) 68    69  /**移除之前已經註冊的滾動改變回調函式。 70   *引數 victim 將要被移除的回撥函式 71   *異常 IllegalStateException 如果isAlive() 返回false 72   */ 73  public void removeOnScrollChangedListener (ViewTreeObserver.OnScrollChangedListener victim) 74   75  /**移除之前已經註冊的觸控模式改變回調函式 76   *引數 victim 將要被移除的回撥函式 77   *異常  IllegalStateException 如果isAlive() 返回false 78   */ 79  public void removeOnTouchModeChangeListener (ViewTreeObserver.OnTouchModeChangeListener victim)

複製程式碼

我們知道在oncreate中View.getWidth和View.getHeight無法獲得一個view的高度和寬度,這是因為View元件佈局要在onResume回撥後完成。所以現在需要使用getViewTreeObserver().addOnGlobalLayoutListener()來獲得寬度或者高度。這是獲得一個view的寬度和高度的方法之一。

OnGlobalLayoutListener 是ViewTreeObserver的內部類,當一個檢視樹的佈局發生改變時,可以被ViewTreeObserver監聽到,這是一個註冊監聽檢視樹的觀察者(observer),在檢視樹的全域性事件改變時得到通知。ViewTreeObserver不能直接例項化,而是通過getViewTreeObserver()獲得。

除了OnGlobalLayoutListener ,ViewTreeObserver還有如下內部類:

interface ViewTreeObserver.OnGlobalFocusChangeListener當在一個檢視樹中的焦點狀態發生改變時,所要呼叫的回撥函式的介面類interface ViewTreeObserver.OnGlobalLayoutListener當在一個檢視樹中全域性佈局發生改變或者檢視樹中的某個檢視的可視狀態發生改變時,所要呼叫的回撥函式的介面類interface ViewTreeObserver.OnPreDrawListener當一個檢視樹將要繪製時,所要呼叫的回撥函式的介面類interface ViewTreeObserver.OnScrollChangedListener當一個檢視樹中的一些元件發生滾動時,所要呼叫的回撥函式的介面類interface ViewTreeObserver.OnTouchModeChangeListener當一個檢視樹的觸控模式發生改變時,所要呼叫的回撥函式的介面類

其中,我們可以利用OnGlobalLayoutListener來獲得一個檢視的真實高度

[java] view plain copy print?
  1. int mHeaderViewHeight;  
  2. mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener(  
  3.         new OnGlobalLayoutListener() {  
  4.             @Override
  5.             publicvoid onGlobalLayout() {  
  6.                 mHeaderViewHeight = mHeaderView.getHeight();  
  7.                 getViewTreeObserver()  
  8.                         .removeGlobalOnLayoutListener(this);  
  9.             }  
  10.         });  

但是需要注意的是OnGlobalLayoutListener可能會被多次觸發,因此在得到了高度之後,要將OnGlobalLayoutListener登出掉。

有時候需要在onCreate方法中知道某個View元件的寬度和高度等資訊,而直接呼叫View元件的getWidth()、getHeight()、getMeasuredWidth()、getMeasuredHeight()、getTop()、getLeft()等方法是無法獲取到真實值的,只會得到0。這是因為View元件佈局要在onResume回撥後完成。下面提供實現方法,onGlobalLayout回撥會在view佈局完成時自動呼叫:

類似:

[java] view plain copy print?
  1. // This listener is used to get the final width of the GridView and then calculate the
  2. // number of columns and the width of each column. The width of each column is variable
  3. // as the GridView has stretchMode=columnWidth. The column width is used to set the height
  4. // of each view so we get nice square thumbnails.
  5. mGridView.getViewTreeObserver().addOnGlobalLayoutListener( //view 佈局完成時呼叫,每次view改變時都會呼叫
  6.         new ViewTreeObserver.OnGlobalLayoutListener() {  
  7.             @Override
  8.             publicvoid onGlobalLayout() {  
  9.                 if (mAdapter.getNumColumns() == 0) {  
  10.                         finalint numColumns = (int) Math.floor(  
  11.                                  mGridView.getWidth() / (mImageThumbSize + mImageThumbSpacing));  
  12.                     if (numColumns > 0) {  
  13.                         finalint columnWidth =  
  14.                             (mGridView.getWidth() / numColumns) - mImageThumbSpacing;  
  15.                         mAdapter.setNumColumns(numColumns);   //設定 列數
  16.                             mAdapter.setItemHeight(columnWidth);  //設定 高度
  17.                     }  
  18.                 }  
  19.             }  
  20.         });  

在gridview佈局完成後,根據girdview的寬和高設定adapter列數和每個item高度