android基礎-viewgroup的測量,佈局,繪製
知識點
- viewgroup的測量
- viewgroup的佈局
- viewgroup的繪製
一、viewgroup的測量
viewgroup的作用主要用於管理子view,而在測量的時候可以分兩種情況
- 當viewgroup的大小設定為 wrap_content的時候 : viewgroup就需要對子view進行遍歷,以便於獲取每個子view的大小,從而來決定自身大小
- 當viewgroup的大小設定為上述的其他模式的時候: 就會通過具體的大小來設定自身的大小
關於viewgroup遍歷子view去測量的方法,android中已經幫我們封裝了兩個常用方法:
protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec)
protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed)
從方法名和方法裡面不難看出這兩個方法的區別,就是後者把子view的padding和margin也考慮了進去,不過他們最終呼叫的都是子view的view.measure(int wSpec,int hSpec)方法也就是之前講過的view自身測量的方法
最後在測量子view之後,就要對自身大小做決定了,同樣是根據不同的測量模式來確定最終的大小,並且最後需要呼叫
protected final void setMeasuredDimension(int measuredWidth, int measuredHeight)
該方法來設定viewgroup的寬高
viewgroup的測量栗子如下:
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //測量子view measureChildren(widthMeasureSpec,heightMeasureSpec); int wModeSpec=MeasureSpec.getMode(widthMeasureSpec); int wSizeSpec=MeasureSpec.getSize(widthMeasureSpec); //這裡只做了寬的測量,高度的測量也是類似的 int resuletW=myMeasureWidth(wModeSpec,wSizeSpec); setMeasuredDimension(resuletW,heightMeasureSpec); } privateint myMeasureWidth(int specMode,int specSize){ int result=0; if(specMode==MeasureSpec.EXACTLY){ //精準模式直接賦值 result=specSize; }else if(specMode==MeasureSpec.AT_MOST){ //這裡一般根據viewgroup的型別來做處理,比如framelayout,linearlayout這些型別 //對於linearlayout類可以如下 for (int i = 0; i < getChildCount(); i++) { View view = getChildAt(i); result += view.getMeasuredWidth(); } //對於framelayout這種型別,我們只需取最大的就好 //for (int i = 0; i < getChildCount(); i++) { //View view = getChildAt(i); //result = view.getMeasuredWidth() > result ? view.getMeasuredWidth() : result; //} }else { //剩餘的這種模式就是沒限制大小的模式了,一般用於recyclerview這種可以擴充套件的佈局形式 //具體的測量方法就是看實際需求了 } return result; }
二、viewgroup的佈局
在自定義viewgroup的時候,我們必須重寫如下方法:
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { }
該方法主要就是通知子view去設定他們的佈局位置,之前android基礎-view的測量,佈局,繪製 的篇章也已經詳細說明了view.layout方法的過程
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // 子view數目 int childCount = getChildCount(); // 垂直襬放子view for (int i = 0;i<childCount;i++){ View childView = getChildAt(i); int height = childView.getMeasuredHeight(); childView.layout(l, i*height, r, t + (i+1)*height); } //這裡擺放子view的設計也是根據實際需要,這裡這做個簡單的例子 }
三、viewgroup的繪製
viewgroup通知情況下不需要繪製,因為他本身就沒有需要繪製的東西,如果不是指定了viewgroup的背景色,那麼viewgroup的onDraw方法都不會被呼叫。但是,viewgroup會使用dispatchDraw()方法來繪製其子view,其過程同樣是通過變遍歷所有的子view,並呼叫子view的繪製方法來完成繪製工作
@Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); }
注意對於viewgroup而言onDraw()先於dispatchDraw()執行,用於本身控制元件的繪製,dispatchDraw()用於子控制元件的繪製,所以如果想對於viewgroup中繪製完子view之後在對其修改,我們可以在dispatchDraw呼叫surper方法之後做自己想要的繪製效果,這樣避免了被子view的覆蓋
總結
viewgroup的測量,佈局,繪製,其實都只是用來管理和通知子view去具體實現,可能最主要就是onLayout方法去定義子view的顯示位置,其他的核心都是在view中做處理的,所以先理解清楚view的顯示過程,那麼再來理解viewgroup的顯示過程,就會容易理解許多
參考文章
《Android群英傳》