1. 程式人生 > >view繪製過程筆記

view繪製過程筆記

view繪製過程

繪製過程由Viewroot的perfortraversals 開始依次呼叫performMeasure,performlayout,performondraw,performMeasure回撥用onmeasure方法,ommeasure方法會遍歷子view,依次呼叫measure,子view也會重複這個動作,onlayout,ondraw也和這個一樣

view的measure

MeasureSpec

由兩部分組成,size,mode

  • EXACYLY 父類已經檢測出大小,就是size
  • AT_MOST 指定一個值(size),子view的寬高不超過這個值(size)
  • UNSPECFIED 不限制大小,隨便多大

父view建立子view的MeasureSpec規則

  • 如果view是固定寬高,不管父viewgroup是什麼,都是EXACTLY,size就是父view的剩餘寬高
  • 如果view是match_parent,父容器是EXACTLY,子view也是EXACTLY,寬高就是父容器剩餘寬高,父容器是AT_MOST,子view就是AT_MOST,寬高不超過父容器剩餘寬高
  • 如果view是wrap_content,不管父容器什麼模式,他都是AT_MOST,並且寬高都是父容器的剩餘寬高

父view在測量的時候會遍歷子view,根據自身的specMode,和view的layoutparms根據上面規則來獲得子view的MeasureSpec

View測量過程

在onmesure中根據MeasureSpec引數來呼叫setmeasureDimension()方法設定寬高

  • EXACYLY 直接設定Size為寬高
  • AT_MOST 直接設定Size為寬高
  • UNSPECFIED 根據minwidth(view屬性)和background寬高,誰大用誰的

因為AT_MOST中的Size是父view的剩餘寬高,直接用的話和match_parent效果一樣,所以我們需要自己處理一下,一般是先設定一個預設寬高,判斷如果是AT_MOST模式就設定預設的寬高

viewgroup由於不同的容器,子view排列的位置也不確定,所以onmeasure方法是自己實現,如果是EXACTLY測量過程和view一樣,如果是AT_MOST,linearlayout會根據方向的不同測量時會遍歷子view,把高度或者寬度累加,就是linearlayout寬高了

Measure(0,0)

view呼叫measure(0,0)的時候實際上是呼叫告訴view使用UNSPECFIED模式來測量,就是你本來就多大就多大,沒有限制,實際上就是 minwidth(view屬性值)和minBackground的最大值,textview就是內容實際高度,getmeasurewidth拿到的值跟xml中width,height無關,所以在wrap_content的時候用measure(0,0)才可能是準的,內容超過父view剩餘高度的話,也會不準

layout

layout 和 onlayout

layout是確定自己的位置呼叫setfram來確定了自己的位置,然後呼叫onlayout,在view中是空實現,每個viewgroup都有自己的實現,基本就是遍歷子view然後根據自己的規則來確定每個子view的位置

在linearlayout中會根據方向來把寬或者高累加,然後遍歷呼叫子view的layout,

getwidth 和getmeasurewidth區別就是一個是在onmeasure中賦值的一個是在layout中賦值的,如果view沒有重寫layout兩個值就是相等的

draw

  1. 繪製背景
  2. 繪製自己
  3. 繪製子view
  4. 繪製裝飾