关于ViewTreeObserver的理解
生活随笔
收集整理的這篇文章主要介紹了
关于ViewTreeObserver的理解
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
作用:通過(guò)名字就可以知道它是View樹(shù)的觀察者,當(dāng)View樹(shù)的發(fā)生變化的時(shí)候會(huì)發(fā)出通知。ViewTreeObserver是不能被應(yīng)用程序?qū)嵗?#xff0c;因?yàn)樗怯梢晥D提供的,通過(guò)view.getViewTreeObserver()獲取。
熟悉觀察者模式的人應(yīng)該很容易想到,為了能夠相應(yīng)的通知,我們肯定需要注冊(cè)監(jiān)聽(tīng)。下面來(lái)看看我們可以注冊(cè)哪些監(jiān)聽(tīng)。
1、當(dāng)在一個(gè)視圖樹(shù)中的焦點(diǎn)狀態(tài)或者可見(jiàn)性發(fā)生改變時(shí)調(diào)用OnGlobalFocusChangeListener的onGlobalFocusChanged()函數(shù)。
public void addOnGlobalFocusChangeListener (ViewTreeObserver.OnGlobalFocusChangeListener listener)
1
1
2、當(dāng)在一個(gè)視圖樹(shù)中的焦點(diǎn)狀態(tài)或者可見(jiàn)性發(fā)生改變時(shí)調(diào)用OnGlobalFocusChangeListener的onGlobalFocusChanged()函數(shù)。
public void addOnGlobalLayoutListener (ViewTreeObserver.OnGlobalLayoutListener listener)
1
1
3、當(dāng)一個(gè)視圖樹(shù)將要繪制時(shí)調(diào)用OnPreDrawListener的onPreDraw()函數(shù)
public void addOnPreDrawListener (ViewTreeObserver.OnPreDrawListener listener)
1
1
4、當(dāng)一個(gè)視圖發(fā)生滾動(dòng)時(shí)調(diào)用OnScrollChangedListener的onScrollChanged()函數(shù)
public void addOnScrollChangedListener (ViewTreeObserver.OnScrollChangedListener listener) ?
1
1
5、當(dāng)一個(gè)觸摸模式發(fā)生改變時(shí)調(diào)用OnTouchModeChangeListener的onTouchModeChanged()函數(shù)
public void addOnTouchModeChangeListener (ViewTreeObserver.OnTouchModeChangeListener listener)
1
1
6、當(dāng)一個(gè)視圖樹(shù)繪制時(shí)調(diào)用OnDrawListener的onDraw()函數(shù)
addOnDrawListener(ViewTreeObserver.OnDrawListener listener)?
1
1
7、當(dāng)View樹(shù)綁定到window上的時(shí)候回調(diào)OnWindowAttachListener的onWindowAttached() 函數(shù),當(dāng)它從window上解綁時(shí)調(diào)用OnWindowAttachListener的onWindowDetached()
addOnWindowAttachListener(ViewTreeObserver.OnWindowAttachListener listener)?
1
1
8、當(dāng)window的焦點(diǎn)狀態(tài)發(fā)生改變時(shí),調(diào)用OnWindowFocusChangeListener的onWindowFocusChanged函數(shù)
addOnWindowFocusChangeListener(ViewTreeObserver.OnWindowFocusChangeListener listener)?
1
1
對(duì)應(yīng)這些注冊(cè)的監(jiān)聽(tīng),還有相應(yīng)的刪除監(jiān)聽(tīng)
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
上面注冊(cè)的監(jiān)聽(tīng)都是View樹(shù)發(fā)生變化的時(shí)候,會(huì)被自動(dòng)觸發(fā)回調(diào),如果我們希望手動(dòng)觸發(fā)回調(diào),可以調(diào)用下面函數(shù)
public final void dispatchOnGlobalLayout ()
手動(dòng)觸發(fā)OnGlobalLayoutListener的onGlobalLayout()函數(shù)回調(diào)
public final boolean dispatchOnPreDraw ()
手動(dòng)觸發(fā)OnPreDrawListener的onPreDraw()函數(shù)的回調(diào)
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
另外還是一個(gè)指示當(dāng)前的ViewTreeObserver是否可用的函數(shù)。
public boolean isAlive ()
當(dāng)observer不可用時(shí),任何方法的調(diào)用(除了這個(gè)方法)都將拋出一個(gè)異常。
1
2
3
1
2
3
應(yīng)用場(chǎng)景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
因?yàn)榛卣{(diào)OnPreDrawListener的onPreDraw,表示這個(gè)View準(zhǔn)備進(jìn)行繪制,在繪制之前,這個(gè)View的寬高肯定是已經(jīng)測(cè)量好了,所以這個(gè)時(shí)機(jī)是可以得到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
當(dāng)view的可見(jiàn)狀態(tài)發(fā)生變化的時(shí)候回調(diào)OnGlobalLayoutListener的onGlobalLayout()函數(shù),這個(gè)時(shí)候View的寬高肯定也是已經(jīng)測(cè)量好了,所以這個(gè)時(shí)機(jī)是可以得到view的寬高的。
應(yīng)用場(chǎng)景2:Activity跳轉(zhuǎn)動(dòng)畫
ViewTreeObserver還可以用來(lái)監(jiān)聽(tīng)根布局,用來(lái)實(shí)現(xiàn)Activity跳轉(zhuǎn)動(dòng)畫,核心代碼如下:
@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;
? ? ? ? ? ? }
? ? ? ? });
? ? }
}
因?yàn)樵诶L制之前會(huì)觸發(fā)OnPreDrawListener的onPreDraw()函數(shù),這個(gè)時(shí)候可以執(zhí)行跳轉(zhuǎn)動(dòng)畫。
應(yīng)用場(chǎng)景3:測(cè)量軟鍵盤狀態(tài)和高度
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監(jiān)聽(tīng),通過(guò)getWindowVisibleDisplayFrame方法可以觀察可見(jiàn)區(qū)域的變化,鍵盤打開(kāi)后 會(huì)影響可見(jiàn)區(qū)域的大小,導(dǎo)致Rect的底部r1.bottom變小。
熟悉觀察者模式的人應(yīng)該很容易想到,為了能夠相應(yīng)的通知,我們肯定需要注冊(cè)監(jiān)聽(tīng)。下面來(lái)看看我們可以注冊(cè)哪些監(jiān)聽(tīng)。
1、當(dāng)在一個(gè)視圖樹(shù)中的焦點(diǎn)狀態(tài)或者可見(jiàn)性發(fā)生改變時(shí)調(diào)用OnGlobalFocusChangeListener的onGlobalFocusChanged()函數(shù)。
public void addOnGlobalFocusChangeListener (ViewTreeObserver.OnGlobalFocusChangeListener listener)
1
1
2、當(dāng)在一個(gè)視圖樹(shù)中的焦點(diǎn)狀態(tài)或者可見(jiàn)性發(fā)生改變時(shí)調(diào)用OnGlobalFocusChangeListener的onGlobalFocusChanged()函數(shù)。
public void addOnGlobalLayoutListener (ViewTreeObserver.OnGlobalLayoutListener listener)
1
1
3、當(dāng)一個(gè)視圖樹(shù)將要繪制時(shí)調(diào)用OnPreDrawListener的onPreDraw()函數(shù)
public void addOnPreDrawListener (ViewTreeObserver.OnPreDrawListener listener)
1
1
4、當(dāng)一個(gè)視圖發(fā)生滾動(dòng)時(shí)調(diào)用OnScrollChangedListener的onScrollChanged()函數(shù)
public void addOnScrollChangedListener (ViewTreeObserver.OnScrollChangedListener listener) ?
1
1
5、當(dāng)一個(gè)觸摸模式發(fā)生改變時(shí)調(diào)用OnTouchModeChangeListener的onTouchModeChanged()函數(shù)
public void addOnTouchModeChangeListener (ViewTreeObserver.OnTouchModeChangeListener listener)
1
1
6、當(dāng)一個(gè)視圖樹(shù)繪制時(shí)調(diào)用OnDrawListener的onDraw()函數(shù)
addOnDrawListener(ViewTreeObserver.OnDrawListener listener)?
1
1
7、當(dāng)View樹(shù)綁定到window上的時(shí)候回調(diào)OnWindowAttachListener的onWindowAttached() 函數(shù),當(dāng)它從window上解綁時(shí)調(diào)用OnWindowAttachListener的onWindowDetached()
addOnWindowAttachListener(ViewTreeObserver.OnWindowAttachListener listener)?
1
1
8、當(dāng)window的焦點(diǎn)狀態(tài)發(fā)生改變時(shí),調(diào)用OnWindowFocusChangeListener的onWindowFocusChanged函數(shù)
addOnWindowFocusChangeListener(ViewTreeObserver.OnWindowFocusChangeListener listener)?
1
1
對(duì)應(yīng)這些注冊(cè)的監(jiān)聽(tīng),還有相應(yīng)的刪除監(jiān)聽(tīng)
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
上面注冊(cè)的監(jiān)聽(tīng)都是View樹(shù)發(fā)生變化的時(shí)候,會(huì)被自動(dòng)觸發(fā)回調(diào),如果我們希望手動(dòng)觸發(fā)回調(diào),可以調(diào)用下面函數(shù)
public final void dispatchOnGlobalLayout ()
手動(dòng)觸發(fā)OnGlobalLayoutListener的onGlobalLayout()函數(shù)回調(diào)
public final boolean dispatchOnPreDraw ()
手動(dòng)觸發(fā)OnPreDrawListener的onPreDraw()函數(shù)的回調(diào)
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
另外還是一個(gè)指示當(dāng)前的ViewTreeObserver是否可用的函數(shù)。
public boolean isAlive ()
當(dāng)observer不可用時(shí),任何方法的調(diào)用(除了這個(gè)方法)都將拋出一個(gè)異常。
1
2
3
1
2
3
應(yīng)用場(chǎng)景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
因?yàn)榛卣{(diào)OnPreDrawListener的onPreDraw,表示這個(gè)View準(zhǔn)備進(jìn)行繪制,在繪制之前,這個(gè)View的寬高肯定是已經(jīng)測(cè)量好了,所以這個(gè)時(shí)機(jī)是可以得到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
當(dāng)view的可見(jiàn)狀態(tài)發(fā)生變化的時(shí)候回調(diào)OnGlobalLayoutListener的onGlobalLayout()函數(shù),這個(gè)時(shí)候View的寬高肯定也是已經(jīng)測(cè)量好了,所以這個(gè)時(shí)機(jī)是可以得到view的寬高的。
應(yīng)用場(chǎng)景2:Activity跳轉(zhuǎn)動(dòng)畫
ViewTreeObserver還可以用來(lái)監(jiān)聽(tīng)根布局,用來(lái)實(shí)現(xiàn)Activity跳轉(zhuǎn)動(dòng)畫,核心代碼如下:
@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;
? ? ? ? ? ? }
? ? ? ? });
? ? }
}
因?yàn)樵诶L制之前會(huì)觸發(fā)OnPreDrawListener的onPreDraw()函數(shù),這個(gè)時(shí)候可以執(zhí)行跳轉(zhuǎn)動(dòng)畫。
應(yīng)用場(chǎng)景3:測(cè)量軟鍵盤狀態(tài)和高度
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監(jiān)聽(tīng),通過(guò)getWindowVisibleDisplayFrame方法可以觀察可見(jiàn)區(qū)域的變化,鍵盤打開(kāi)后 會(huì)影響可見(jiàn)區(qū)域的大小,導(dǎo)致Rect的底部r1.bottom變小。
總結(jié)
以上是生活随笔為你收集整理的关于ViewTreeObserver的理解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 关于音频焦点的理解
- 下一篇: 视频播放器的界面设计并实现播放器