ViewGroup為什麼不會呼叫onDraw
正常情況下,我們重寫LinearLayout的onDraw方法,它是不會被呼叫的,這篇文章就來分析一下原因和解決方法。
一,現象
<com.test.demo.MyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/ll_absolute"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#FF000000">
</com.test.demo.MyLinearLayout>
大概的架構是,MyLinearLayout從LinearLayout派生出來,然後在程式中過載OnDraw(Canvas canvas)。但是,onDraw不會被呼叫。我們可能會遇到這個問題:如果不給LinearLayout設定一個背景,系統是不會呼叫onDraw時,也就是說,我們重寫的onDraw是不會呼叫的。當設定一個背景後,onDraw就會被呼叫。
二,原因
造成這種現象的原因是繼承自LinearLayout,而LinearLayout這是一個容器,ViewGroup嘛,它本身並沒有任何可畫的東西,它是一個透明的控制元件,因些並不會觸發onDraw,但是你現在給LinearLayout設定一個背景色,其實這個背景色不管你設定成什麼顏色,系統會認為,這個LinearLayout上面有東西可畫了,因此會呼叫onDraw方法。
我們可以仔細分析View的原始碼,它有一個方法View#draw(Canvas)方法,這裡面有兩個地方呼叫onDraw,它的條件都是:
if (!dirtyOpaque) onDraw(canvas);
也就是說,如果dirtyOpaque是true的話,onDraw就不會呼叫,而dirtyOpaque的值的計算程式碼如下:
- finalbooleandirtyOpaque=(privateFlags&DIRTY_MASK)==DIRTY_OPAQUE&&
- (mAttachInfo==null||!mAttachInfo.mIgnoreDirtyState);
// Opaque if:
// - Has a background
// - Background is opaque
// - Doesn't have scrollbars or scrollbars are inside overlay
View還提供了一個重要的方法:setWillNotDraw,我們看一看它的實現:
- /**
- *Ifthisviewdoesn'tdoanydrawingonitsown,setthisflagto
- *allowfurtheroptimizations.Bydefault,thisflagisnotseton
- *View,butcouldbesetonsomeViewsubclassessuchasViewGroup.
- *
- *Typically,ifyouoverride{@link#onDraw}youshouldclearthisflag.
- *
- *@paramwillNotDrawwhetherornotthisViewdrawonitsown
- */
- publicvoidsetWillNotDraw(booleanwillNotDraw){
- setFlags(willNotDraw?WILL_NOT_DRAW:0,DRAW_MASK);
- }
從這個方法的註釋,我們可以看出,如果你想重寫onDraw的話,你應該呼叫這個方法來清除flag,所以如果我們想要重寫LinearLayout的onDraw的話,我們也可以在其構造方法中呼叫setWillNotDraw方法。 在ViewGroup初始他時,它呼叫了一個私有方法:initViewGroup,它裡面會有一句setFlags(WILL_NOT_DRAW, DRAW_MASK); 相當於呼叫了setWillNotDraw(true),所以說,對於ViewGroup,它就認為是透明的了。如果我們想要重寫onDraw,就需要呼叫setWillNotDraw(false)
三,總結一下:
1)ViewGroup預設情況下,會被設定成WILL_NOT_DRAW,這是從效能考慮,這樣一來,onDraw就不會被呼叫了。
2)如果我們要重要一個ViweGroup的onDraw方法,有兩種方法:
1,在建構函式裡面,給其設定一個顏色,如#00000000。
2,在建構函式裡面,呼叫setWillNotDraw(false),去掉其WILL_NOT_DRAW flag。
相關文章
- 你真的瞭解Android ViewGroup的draw和onDraw的呼叫時機嗎AndroidView
- 網站為什麼會打不開網站
- 為什麼新人不會程式設計程式設計
- SQL語句為什麼不會共享(上)SQL
- SQL語句為什麼不會共享(中)SQL
- SQL語句為什麼不會共享(下)SQL
- 為什麼Facebook不會有“dislike”按鈕?
- 這就是為什麼你學不會DDD
- Python 的切片為什麼不會索引越界?Python索引
- GreatSQL 中為什麼 Update 不會被鎖等待SQL
- 為什麼這麼多人學不會C語言呢?C語言
- 為什麼你還是學不會程式設計程式設計
- 為什麼RPG遊戲永遠不會過時?遊戲
- 你為什麼總是學不會設計模式?設計模式
- 我為什麼會從程式不喜歡加{}到加{}
- 為什麼有的程式設計師不會程式設計?程式設計師
- 下一個成為IE會不會是Chrome,看看是什麼情況。Chrome
- 為什麼react在setTimeOut中使用setSate不會批量更新React
- 為什麼人工智慧不會讓軟體測試消失人工智慧
- oracle為什麼不走索引Oracle索引
- 為什麼說會不會SQL,決定著你的工資?方向不對,努力也白費!SQL
- phpstrom用模型where查詢,欄位為什麼不會提示?PHP模型
- 執行緒崩潰為什麼不會導致 JVM 崩潰執行緒JVM
- Python能幹什麼?為什麼會火?Python
- 3 * 0.1 == 0.3將會返回什麼?為什麼?
- JS 裡為什麼會有 thisJS
- 為什麼專案會延期?
- 你為什麼不愛遊戲了?遊戲
- 騰訊為什麼不投資技術?
- 我為什麼不喜歡框架框架
- 為什麼 useState 多次更新不生效?
- 為什麼不建議使用gotoGo
- 為什麼 Go 裡值為 nil 可以呼叫函式?Go函式
- 為什麼說共享WiFi專案是如今風口,會不會已經太晚了!WiFi
- Python能幹什麼?為什麼會這麼火?Python
- 為什麼新的資料庫會議還在不斷早開?資料庫
- 3D 高斯噴濺 🤗 為什麼圖形永遠不會相同3D
- 做了這麼多年前端,為什麼你還是不會寫業務程式碼?前端