可將整個繪制過程分為三部分:Measure - Layout - Draw? 自定義ViewGrop? onMeasure() onLayout()? ? 自定義View則? onMeasure()? ?onDraw()
自定義View的四個構(gòu)造器
構(gòu)造函數(shù)參數(shù)說明:
Context - 上下文绷落;
AttributeSet - xml文件中的屬性;
int defStyleAttr - Theme中的默認樣式筐喳;
int defStyleResource - defStyleAttr未使用(為0函喉,或者未匹配到),則應用于View的默認樣式函似;
R.style中系統(tǒng)為view定義了很多默認主題Theme,主題中有對某些屬性的默認賦值撇寞。
Measure 過程(自定義ViewGroup)
1. 先測量子視圖再測量父視圖
父視圖會調(diào)用子視圖的onMeasure(widthMeasureSpec ,heightmeasurespec) 子視圖會調(diào)用子視圖的onMeasure遞歸調(diào)用直到?jīng)]有子視圖結(jié)束調(diào)用.自定義View中重寫的OnMeasure參數(shù)來自于父布局堂氯。
測量子視圖通過getChildCound? 獲得子View個數(shù)逐個測量調(diào)用ChildView.setMeasure(childwidthMeasureSpec,childhetihtMeasureSpec)牌废,這個參數(shù)的來源不僅僅是LayoutParmes. 通過提供的getChildWidthMeasureSpec(父視圖的Spec,padding,childview大小)計算得到
我們知道子視圖的寬度高度在xml分為三種模式一種是確定大小的dp一種是warpcontent 一種是不確定的。通過child.getLayoutParmes獲取每一個子視圖的參數(shù)最后測量父視圖通過setMeasuredDimension(width,height)設置值并保存里面的值如果父布局是Extially 從父布局的widthMeasureSpec 獲取晶框,否則就通過子view累加獲得
Layout 過程
1. 在Layout過程中懂从,子視圖會調(diào)用getMeasuredWidth()和getMeasuredHeight()方法獲取到measure過程得到mMeasuredWidth和mMeasuredHeight,作為自己的width和height番甩。然后調(diào)用每一個子視圖的layout(),來確定每個子視圖在父視圖中的位置窍育。
layout(l ,r,t,b)涉及到view的坐標系 layout也是z子View先布局然后父view再布局.子view的left? right? bottom top都是通過子視圖getMeasureWidth算出來 宴胧。getwidth()方法是onLayout之后才能調(diào)用,? ?getmeasurewidth()則是通過測量之后setMeasureDimension()設置保存的
Draw 過程
1. dispatchDraw()發(fā)起對子視圖的繪制,在View中默認為空實現(xiàn)乞娄,ViewGroup復寫了dispatchDraw()來對其子視圖進行繪制。
tip1.不要將初始化參數(shù)放到OnMeasure中因為OnMeasure多次調(diào)用容易內(nèi)存抖動
tip2.自定義ViewGroup的 時候 整體的寬高會加上padding? 子視圖會去掉padding
tip3.測量的時候要判斷子視圖是否可見
tip4,onLyout的時候要考慮gravity