关于ViewTreeObserver的理解
生活随笔
收集整理的這篇文章主要介紹了
关于ViewTreeObserver的理解
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
作用:通過名字就可以知道它是View樹的觀察者,當View樹的發生變化的時候會發出通知。ViewTreeObserver是不能被應用程序實例化的,因為它是由視圖提供的,通過view.getViewTreeObserver()獲取。
熟悉觀察者模式的人應該很容易想到,為了能夠相應的通知,我們肯定需要注冊監聽。下面來看看我們可以注冊哪些監聽。
1、當在一個視圖樹中的焦點狀態或者可見性發生改變時調用OnGlobalFocusChangeListener的onGlobalFocusChanged()函數。
public void addOnGlobalFocusChangeListener (ViewTreeObserver.OnGlobalFocusChangeListener listener)
1
1
2、當在一個視圖樹中的焦點狀態或者可見性發生改變時調用OnGlobalFocusChangeListener的onGlobalFocusChanged()函數。
public void addOnGlobalLayoutListener (ViewTreeObserver.OnGlobalLayoutListener listener)
1
1
3、當一個視圖樹將要繪制時調用OnPreDrawListener的onPreDraw()函數
public void addOnPreDrawListener (ViewTreeObserver.OnPreDrawListener listener)
1
1
4、當一個視圖發生滾動時調用OnScrollChangedListener的onScrollChanged()函數
public void addOnScrollChangedListener (ViewTreeObserver.OnScrollChangedListener listener) ?
1
1
5、當一個觸摸模式發生改變時調用OnTouchModeChangeListener的onTouchModeChanged()函數
public void addOnTouchModeChangeListener (ViewTreeObserver.OnTouchModeChangeListener listener)
1
1
6、當一個視圖樹繪制時調用OnDrawListener的onDraw()函數
addOnDrawListener(ViewTreeObserver.OnDrawListener listener)?
1
1
7、當View樹綁定到window上的時候回調OnWindowAttachListener的onWindowAttached() 函數,當它從window上解綁時調用OnWindowAttachListener的onWindowDetached()
addOnWindowAttachListener(ViewTreeObserver.OnWindowAttachListener listener)?
1
1
8、當window的焦點狀態發生改變時,調用OnWindowFocusChangeListener的onWindowFocusChanged函數
addOnWindowFocusChangeListener(ViewTreeObserver.OnWindowFocusChangeListener listener)?
1
1
對應這些注冊的監聽,還有相應的刪除監聽
public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)
public void removeOnGlobalFocusChangeListener (ViewTreeObserver.OnGlobalFocusChangeListener victim)
public void removeOnPreDrawListener (ViewTreeObserver.OnPreDrawListener victim)
public void removeOnScrollChangedListener (ViewTreeObserver.OnScrollChangedListener victim)
public void removeOnTouchModeChangeListener (ViewTreeObserver.OnTouchModeChangeListener victim)
public void removeOnDrawListener(ViewTreeObserver.OnDrawListener victim)?
public void removeOnWindowAttachListener(ViewTreeObserver.OnWindowAttachListener victim)?
public void removeOnWindowFocusChangeListener(ViewTreeObserver.OnWindowFocusChangeListener victim)?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
上面注冊的監聽都是View樹發生變化的時候,會被自動觸發回調,如果我們希望手動觸發回調,可以調用下面函數
public final void dispatchOnGlobalLayout ()
手動觸發OnGlobalLayoutListener的onGlobalLayout()函數回調
public final boolean dispatchOnPreDraw ()
手動觸發OnPreDrawListener的onPreDraw()函數的回調
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
另外還是一個指示當前的ViewTreeObserver是否可用的函數。
public boolean isAlive ()
當observer不可用時,任何方法的調用(除了這個方法)都將拋出一個異常。
1
2
3
1
2
3
應用場景1:獲取View的寬高
@Override
protected void onCreate(Bundle savedInstanceState) {
? ? super.onCreate(savedInstanceState);
? ? setContentView(R.layout.activity_main);
? ? final MyImageView myImageView = (MyImageView) findViewById(R.id.imageview);
? ? int height = 0;
? ? int width = ?0 ;
? ? ViewTreeObserver vto = myImageView.getViewTreeObserver();
? ? vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
? ? ? ? public boolean onPreDraw() {
? ? ? ? ? ? int height = myImageView.getMeasuredHeight();
? ? ? ? ? ? int width = myImageView.getMeasuredWidth();
? ? ? ? ? ? return true;
? ? ? ? }
? ? });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
因為回調OnPreDrawListener的onPreDraw,表示這個View準備進行繪制,在繪制之前,這個View的寬高肯定是已經測量好了,所以這個時機是可以得到view的寬高的。
@Override
protected void onCreate(Bundle savedInstanceState) {
? ? super.onCreate(savedInstanceState);
? ? setContentView(R.layout.activity_main);
? ? final MyImageView myImageView = (MyImageView) findViewById(R.id.imageview);
? ? int height = 0;
? ? int width = ?0 ;
? ? ViewTreeObserver vto = myImageView.getViewTreeObserver();
? ? vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
? ? ? ? @Override
? ? ? ? public void onGlobalLayout() {
? ? ? ? ? ? myImageView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
? ? ? ? ? ? int height = myImageView.getHeight();
? ? ? ? ? ? int width = myImageView.getWidth();
? ? ? ? }
? ? });?
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
當view的可見狀態發生變化的時候回調OnGlobalLayoutListener的onGlobalLayout()函數,這個時候View的寬高肯定也是已經測量好了,所以這個時機是可以得到view的寬高的。
應用場景2:Activity跳轉動畫
ViewTreeObserver還可以用來監聽根布局,用來實現Activity跳轉動畫,核心代碼如下:
@Override
public void onCreate(Bundle savedInstanceState) {
? ? super.onCreate(savedInstanceState);
? ? setContentView(R.layout.activity_second);
? ? rootView = findViewById(R.id.root);
? ? if (savedInstanceState == null) {
? ? ? ? rootView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public boolean onPreDraw() {
? ? ? ? ? ? ? ? rootView.getViewTreeObserver().removeOnPreDrawListener(this);
? ? ? ? ? ? ? ? startRootAnimation();
? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? }
? ? ? ? });
? ? }
}
因為在繪制之前會觸發OnPreDrawListener的onPreDraw()函數,這個時候可以執行跳轉動畫。
應用場景3:測量軟鍵盤狀態和高度
ViewTreeObserver.OnGlobalLayoutListener mListener = new ViewTreeObserver
? ? ? ? ? ? .OnGlobalLayoutListener() {
? ? ? ? public void onGlobalLayout() {
? ? ? ? ? ? Rect r1 = new Rect();
? ? ? ? ? ? root.getWindowVisibleDisplayFrame(r1);
? ? ? ? ? ? Log.e("TAG",r1.bottom+"") ;?
? ? ? ? }
? ? };
root.getViewTreeObserver().addOnGlobalLayoutListener(mListener);
在根布局加入GlobalLayoutListener監聽,通過getWindowVisibleDisplayFrame方法可以觀察可見區域的變化,鍵盤打開后 會影響可見區域的大小,導致Rect的底部r1.bottom變小。
熟悉觀察者模式的人應該很容易想到,為了能夠相應的通知,我們肯定需要注冊監聽。下面來看看我們可以注冊哪些監聽。
1、當在一個視圖樹中的焦點狀態或者可見性發生改變時調用OnGlobalFocusChangeListener的onGlobalFocusChanged()函數。
public void addOnGlobalFocusChangeListener (ViewTreeObserver.OnGlobalFocusChangeListener listener)
1
1
2、當在一個視圖樹中的焦點狀態或者可見性發生改變時調用OnGlobalFocusChangeListener的onGlobalFocusChanged()函數。
public void addOnGlobalLayoutListener (ViewTreeObserver.OnGlobalLayoutListener listener)
1
1
3、當一個視圖樹將要繪制時調用OnPreDrawListener的onPreDraw()函數
public void addOnPreDrawListener (ViewTreeObserver.OnPreDrawListener listener)
1
1
4、當一個視圖發生滾動時調用OnScrollChangedListener的onScrollChanged()函數
public void addOnScrollChangedListener (ViewTreeObserver.OnScrollChangedListener listener) ?
1
1
5、當一個觸摸模式發生改變時調用OnTouchModeChangeListener的onTouchModeChanged()函數
public void addOnTouchModeChangeListener (ViewTreeObserver.OnTouchModeChangeListener listener)
1
1
6、當一個視圖樹繪制時調用OnDrawListener的onDraw()函數
addOnDrawListener(ViewTreeObserver.OnDrawListener listener)?
1
1
7、當View樹綁定到window上的時候回調OnWindowAttachListener的onWindowAttached() 函數,當它從window上解綁時調用OnWindowAttachListener的onWindowDetached()
addOnWindowAttachListener(ViewTreeObserver.OnWindowAttachListener listener)?
1
1
8、當window的焦點狀態發生改變時,調用OnWindowFocusChangeListener的onWindowFocusChanged函數
addOnWindowFocusChangeListener(ViewTreeObserver.OnWindowFocusChangeListener listener)?
1
1
對應這些注冊的監聽,還有相應的刪除監聽
public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)
public void removeOnGlobalFocusChangeListener (ViewTreeObserver.OnGlobalFocusChangeListener victim)
public void removeOnPreDrawListener (ViewTreeObserver.OnPreDrawListener victim)
public void removeOnScrollChangedListener (ViewTreeObserver.OnScrollChangedListener victim)
public void removeOnTouchModeChangeListener (ViewTreeObserver.OnTouchModeChangeListener victim)
public void removeOnDrawListener(ViewTreeObserver.OnDrawListener victim)?
public void removeOnWindowAttachListener(ViewTreeObserver.OnWindowAttachListener victim)?
public void removeOnWindowFocusChangeListener(ViewTreeObserver.OnWindowFocusChangeListener victim)?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
上面注冊的監聽都是View樹發生變化的時候,會被自動觸發回調,如果我們希望手動觸發回調,可以調用下面函數
public final void dispatchOnGlobalLayout ()
手動觸發OnGlobalLayoutListener的onGlobalLayout()函數回調
public final boolean dispatchOnPreDraw ()
手動觸發OnPreDrawListener的onPreDraw()函數的回調
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
另外還是一個指示當前的ViewTreeObserver是否可用的函數。
public boolean isAlive ()
當observer不可用時,任何方法的調用(除了這個方法)都將拋出一個異常。
1
2
3
1
2
3
應用場景1:獲取View的寬高
@Override
protected void onCreate(Bundle savedInstanceState) {
? ? super.onCreate(savedInstanceState);
? ? setContentView(R.layout.activity_main);
? ? final MyImageView myImageView = (MyImageView) findViewById(R.id.imageview);
? ? int height = 0;
? ? int width = ?0 ;
? ? ViewTreeObserver vto = myImageView.getViewTreeObserver();
? ? vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
? ? ? ? public boolean onPreDraw() {
? ? ? ? ? ? int height = myImageView.getMeasuredHeight();
? ? ? ? ? ? int width = myImageView.getMeasuredWidth();
? ? ? ? ? ? return true;
? ? ? ? }
? ? });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
因為回調OnPreDrawListener的onPreDraw,表示這個View準備進行繪制,在繪制之前,這個View的寬高肯定是已經測量好了,所以這個時機是可以得到view的寬高的。
@Override
protected void onCreate(Bundle savedInstanceState) {
? ? super.onCreate(savedInstanceState);
? ? setContentView(R.layout.activity_main);
? ? final MyImageView myImageView = (MyImageView) findViewById(R.id.imageview);
? ? int height = 0;
? ? int width = ?0 ;
? ? ViewTreeObserver vto = myImageView.getViewTreeObserver();
? ? vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
? ? ? ? @Override
? ? ? ? public void onGlobalLayout() {
? ? ? ? ? ? myImageView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
? ? ? ? ? ? int height = myImageView.getHeight();
? ? ? ? ? ? int width = myImageView.getWidth();
? ? ? ? }
? ? });?
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
當view的可見狀態發生變化的時候回調OnGlobalLayoutListener的onGlobalLayout()函數,這個時候View的寬高肯定也是已經測量好了,所以這個時機是可以得到view的寬高的。
應用場景2:Activity跳轉動畫
ViewTreeObserver還可以用來監聽根布局,用來實現Activity跳轉動畫,核心代碼如下:
@Override
public void onCreate(Bundle savedInstanceState) {
? ? super.onCreate(savedInstanceState);
? ? setContentView(R.layout.activity_second);
? ? rootView = findViewById(R.id.root);
? ? if (savedInstanceState == null) {
? ? ? ? rootView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public boolean onPreDraw() {
? ? ? ? ? ? ? ? rootView.getViewTreeObserver().removeOnPreDrawListener(this);
? ? ? ? ? ? ? ? startRootAnimation();
? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? }
? ? ? ? });
? ? }
}
因為在繪制之前會觸發OnPreDrawListener的onPreDraw()函數,這個時候可以執行跳轉動畫。
應用場景3:測量軟鍵盤狀態和高度
ViewTreeObserver.OnGlobalLayoutListener mListener = new ViewTreeObserver
? ? ? ? ? ? .OnGlobalLayoutListener() {
? ? ? ? public void onGlobalLayout() {
? ? ? ? ? ? Rect r1 = new Rect();
? ? ? ? ? ? root.getWindowVisibleDisplayFrame(r1);
? ? ? ? ? ? Log.e("TAG",r1.bottom+"") ;?
? ? ? ? }
? ? };
root.getViewTreeObserver().addOnGlobalLayoutListener(mListener);
在根布局加入GlobalLayoutListener監聽,通過getWindowVisibleDisplayFrame方法可以觀察可見區域的變化,鍵盤打開后 會影響可見區域的大小,導致Rect的底部r1.bottom變小。
總結
以上是生活随笔為你收集整理的关于ViewTreeObserver的理解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于音频焦点的理解
- 下一篇: Android RemoteContro