inflate方法常常用來解析乙個
xml布局檔案,在自定義組合式控制項中常常使用,使用的姿勢包括:
view.inflate(context, resource, root)
layoutinflater.from(getcontext()).inflate(resource, root);
而view.inflate其實還是呼叫的
layoutinflater
去解析乙個
xml:
public static view inflate(context context, int resource, viewgroup root)
所以這兩種姿勢沒啥區別,這裡來討論一下inflate(resouce, root)的返回值,引數
resource
是布局資源,
root
是傳入的乙個根節點。如果
root
傳入乙個
null
,inflate
就會解析
resource
對應的xml
,返回這個
xml中的根節點,如果
root
傳入不為
null
,inflate
會解析這個
xml布局並且新增到根節點
root
下,然後返回根節點
root
。另外還有帶三個引數的inflate方法:
inflate(
intresource, viewgroup root,
boolean
attachtoroot)
這裡多了乙個引數attachtoroot,如果
root
為null
,則返回解析後的
xml布局中的根節點;如果
root
不為null,attachtoroot
為true,inflate
會解析這個
xml布局並且新增到根節點
root
下,然後返回根節點
root
;如果root
不為null,attachtoroot
為false,inflate
會解析這個
xml布局但不會新增到根節點
root
下,然後返回解析後的
xml布局中的根節點,這時候
root
的作用只是為
xml中的根節點提供布局引數的屬性,因為
xml中的根節點不知道自己的父容器是誰,所以如果沒有人給它提供的話,它的布局引數就會失效。
onfinishinflate是當所有的孩子都解析完後的乙個呼叫。比如我們自定義乙個
viewgroup
,想要去找到孩子做一些設定,這時候如果在自定義
viewgroup
的建構函式去
findviewbyid
的話,會返回乙個
null,
因為此時孩子還沒有解析好,也就是還沒有生出來。這時候我們可以去覆寫
onfinishinflate
,當孩子解析好後再去
find
。關於requestlayout的介紹比較多,
requestlayout()
方法會觸發
measure
過程和layout
過程,不會呼叫
draw
過程,也不會重新繪製任何
view
包括該呼叫者本身
onsizechange是控制項的大小發生變化的時候的呼叫,它的呼叫軌跡是
layout->setframe->sizechange->onsizechange
。當控制項第一次布局時肯定會被呼叫到,我們覆寫該方法可以獲取到控制項的大小。所以這個方法通常被用來在裡面初始化跟控制項大小相關的成員變數。
invalidate使用的非常頻繁,它會觸發
view
的重新繪製,也就是繪製流程的
draw
過程,但不會呼叫測量和布局過程
我們都知道android的
ui是單執行緒模型,只能在主線程更新
ui,所以我們只能在主線程呼叫
invalidate,
如果想要在子執行緒更新
ui,可以使用
handler
傳送乙個
msg到主線程,然後在處理
msg的時候去呼叫
invalidate
。另外,我們可以直接呼叫
postinvalidate
去在子執行緒更新ui,
postinvalidate
內部實現也是使用
handler
來做傳送
msg到主線程然後呼叫
invalidate
。自定義viewgroup通常是不會去繪製自己的,如果大家重寫
viewgroup
裡面的draw
方法或者
ondraw
方法會發現它們根本就不會被呼叫到。但是如果給你的
viewgroup
設定乙個背景,就會發現
draw
方法和ondraw
方法又都會走了。
我們知道viewgroup本身是乙個
view,
它的繪製是被其父容器發起的,具體的位置是在
viewgroup
中的drawchild
方法:protected boolean drawchild(canvas canvas, view child, long drawingtime)
注意這裡的draw方法是帶三個引數的,與我們通常講的帶乙個引數的
draw
方法不一樣。在
view
類中找到帶三個引數的
draw
方法,發現裡面有這麼一段**:
if(!hasdisplaylist)
else }
從這裡我們可以看出一點端倪,通常乙個viewgroup預設是會跳過繪製的,也即
(mprivateflags & pflag_skip_draw) == pflag_skip_draw
會返回乙個
true,
那麼會直接走
dispatchdraw
方法去畫它自己的孩子去了,並不會呼叫帶乙個引數的
draw(canvas) ,
但是當這個
viewgroup
有背景或者
setwillnotdraw(false)
是,就會走
draw(canvas)
方法。所以如果我們自定義乙個viewgroup並且想要實現它本身的繪製的話,就可以給它設定乙個背景或者呼叫
setwillnotdraw(false)
onattachedtowindow是當乙個
view
繫結到window
上時的呼叫,根據
view
類裡面的對這個方法的注釋,
onattachedtowindow
肯定會在
ondraw
方法之前呼叫。
在自定義控制項裡面,我們可以在onattachedtowindow註冊一些廣播接收器,觀察者或者開啟一些任務,大家可以參考
textclock
的裡面的實現。
ondetachedfromwindow對應於
onattachedtowindow,
是當乙個
view
從window
上移除時的乙個呼叫。如果在
onattachedwindow
裡面註冊了一些監聽,那麼通常就要在
ondetachedfromwindow
裡面反註冊。
viewtreeobserver是檢視樹的觀察者,監聽一些檢視樹的全域性變化,這些全域性變化包括整個檢視樹的布局,開始繪製,觸控模式的變化等。我們不能直接初始化
viewtreeobserver
的物件,需要通過
getviewtreeobserver()
去獲取。
當在乙個檢視樹中全域性布局發生改變或者檢視樹中的某個檢視的可視狀態發生改變的***,一般的使用姿勢是:
getviewtreeobserver().addongloballayoutlistener(
newongloballayoutlistener()
});當乙個檢視樹將要繪製時的***,一般的使用姿勢是:
getviewtreeobserver().addonpredrawlistener(
newonpredrawlistener()
});
Android 自定義控制項
幹android也有一段的時間了,自定義這塊的東西覺得還是很有比較複習一下基礎的東西。自定義控制項和自定義元件基本上的使用都是在專案中基本的android控制項滿足不了需求的時候使用的。所以,如果要高出特別炫的特效,或者比較特殊的控制項排列方式,例如瀑布流,那麼就要好好學學自定義咯。首先,先簡單的介...
android自定義控制項
android自定義控制項 二 入門,繼承view 說說android 兩種為自定義元件新增屬性的使用方法和區別 自定義控制項的屬性 自定義控制項 今天花了3,4個小時看了自定義控制項,看 懂了,還沒有實踐,因為時間不夠,日後實踐。總結下 自定義控制項有3種方式 繼承已有控制項 繼承乙個容器控制項,...
Android自定義控制項
android學習筆記,整理給自己複習的時候看的,謝謝!1.自定義開關 1.宣告介面物件 public inte ce onswitchstateupdatelistener 2.新增設定介面物件的方法,外部進行呼叫 public void setonswitchstateupdatelistene...