確定View的位置(Layout)
上一章說了有關(guān)View的一些基本知識,以及測量(Measure),就直奔主題了,有興趣的小伙伴可以到主頁看上一篇文章污茵。
layout流程圖
? ? 從第一個?Layout()開始看,點(diǎn)進(jìn)去看源碼發(fā)現(xiàn)葬项,該方法有四個參數(shù)省咨。如下圖
Layout方法源碼解析
(int?left,int?top玷室,int?right零蓉,int?bottom),代表著View對父類的上下左右距離穷缤。有意思的是和平常理解的上下左右敌蜂,有一丟的不一樣,我畫個圖表示一下津肛。
畫圖解釋上下左右
從上圖可以看出來章喉,left?和?top?與我們中國人正常想法是一樣的? 而?right 和?bottom有些不一樣,應(yīng)該是故意這樣的身坐,也很好理解秸脱,因?yàn)檫@樣可以很容易的確定view的大小,拿bottom -?top?得到View的高部蛇,拿right -?left?得到View的寬摊唇。并且,知道了left以及top涯鲁,那么view的位置也就定位到了巷查。大致就是這個樣子有序,需要注意一下。繼續(xù)往下看Layout中的源碼岛请。
layout方法部分代碼旭寿。
? ? ? ? 可以看到一開始做了個if判斷,跳過去先不管崇败,下方是一個位置的賦值不管跳過去盅称,在下方,發(fā)現(xiàn)調(diào)用了一個setFrame方法后室,這個方法可以在最上方的流程圖中看到缩膝,這個setFrame方法是一個隱藏的方法,無法重寫咧擂,內(nèi)部通過比對本次的left,top檀蹋,right松申,bottom四個值,與上次是否相同俯逾,判斷自身的位置和大小是否發(fā)生改變贸桶,如果發(fā)生了改變,會調(diào)用invalidate請求重新繪制桌肴,并記錄本次的left皇筛,top,right坠七,bottom用與下次比對水醋,如果沒發(fā)生變化,就不用重新繪制彪置,setFrame方法的源碼就不貼了拄踪,里面無非就是判斷上下左右(left,top拳魁,...)四個位置的值是否發(fā)生變化惶桐,變化就調(diào)用invalidate方法請求重新繪制,然后將保存新的位置以便下次比較潘懊,然后我們繼續(xù)往下看姚糊,onLayout()方法的源碼。截圖就不貼授舟,上張圖Layout方法中能看到調(diào)用Onlayout救恨,在倒數(shù)第四行代碼。
onLayout方法源碼解析
嗯释树?怎么是個空方法忿薇?懵了吧裙椭?看這個方法上面的英文解釋該方法,了解到這個方法是只有在ViewGroup類型(如linelayout署浩,relativelayout)中需要寫這個方法揉燃,去定位內(nèi)部View或者內(nèi)部ViewGroup的位置,從最上面的Layout定位流程圖可以看的很明白筋栋。如果是單獨(dú)的View炊汤,不需要復(fù)寫onLayout方法,所以我們進(jìn)入到ViewGroup類中弊攘,查找onLayout方法看一下做了什么操作抢腐。
ViewGroup中的onLayout
好家伙,直接變成抽象方法了襟交,我們都知道迈倍,抽象方法,子類必須重新捣域。那我們?nèi)フ乙粋€繼承了ViewGroup的類查一查啼染,拿Linelayout舉例,我們進(jìn)入Linelayout查看onLayout.
Linelayout中的onlayout
因?yàn)長inelayout集成了ViewGroup焕梅,所以必須重寫ViewGroup中的抽象方法(onLayout)迹鹅,終于能讀一下onLayout中的源碼了≌暄裕可以看到里面又調(diào)用了兩個方法斜棚,layoutVertical() 和?layoutHorizontal()?因?yàn)槲覀冇肔inelayout時(shí),要分內(nèi)部View是垂直走向该窗,還是水平走向弟蚀,是這個意思,我們隨便點(diǎn)開一個進(jìn)去看看酗失。
layoutHorizontal部分源碼
我剛剛進(jìn)的是下面那個水平的方法粗梭,這個方法源碼太多太長,只能截一個核心的位置的源碼了级零。
我們一開始在最上面的layout流程圖中可以看到断医,在onLayout之后,是調(diào)用了Child.layout方法奏纪,給ViewGroup里面的孩子(View或者ViewGroup)定位和大小鉴嗤,可在上圖中的layoutHorizontal中,并沒有發(fā)現(xiàn)Child.layout方法序调,那肯定就是調(diào)用了某個方法醉锅,在某個方法中調(diào)用了Child.layout。我們看上圖框住的setChildFrame方法发绢,在這個方法之前呢硬耍,是一些獲取當(dāng)前展示的子View垄琐,然后獲取位置什么的,傳給了setChildFrame方法经柴,我們點(diǎn)進(jìn)去看一下狸窘。
setChildFrame方法源碼