1. 程式人生 > >ViewGroup中的onLayout方法的理解

ViewGroup中的onLayout方法的理解

今天在自定義一個ViewGroup的時候出現了一個這樣問題,事後分析是因為自己對ViewGroup中的onLayout方法和其中子View的layout方法的理解不足導致的。

我要實現的效果是做一個類似LinearLayout垂直排列子View的ViewGroup,在ViewGroup中onMeasure方法中測量完ViewGroup的大小以後進開始擺放子View了,onLayout的開始的程式碼如下:

@Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        int count = getChildCount();
        int curHeight = top;
        for (int i = 0 ; i < count ; i++){
            View childView = getChildAt(i);
            int height = childView.getMeasuredHeight();
            int width = childView.getMeasuredWidth();
            childView.layout(left,curHeight,right + width,bottom + height);

            curHeight += height;
        }
    }

程式碼如下,測試了一下發現當自定義的ViewGroup和其他的View並列的時候就會出現問題,如果子佈局中只有自定義的ViewGroup自己,頁面顯示是沒有問題的。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <Button
    	android:background="#e41212"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="按鈕"
        />

    <!--自定義ViewGroup-->
    <com.emm.datastructure.custom_view.ZHViewGroup
        android:background="#b42666"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <Button
            android:layout_width="wrap_content"
            android:layout_height="100dp"
            android:text="btn"
            />
    </com.emm.datastructure.custom_view.ZHViewGroup>

</LinearLayout>

經過分析發現是ViewGroup中的onLayout程式碼寫錯了,正確的onLayout方法如下:

/**
     *引數左上右下,是指以螢幕的左上角為座標原點的座標
     */
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        int count = getChildCount();
        //記錄當前高度位置。
        //因為在擺放子View的時候,子View的layout方法是以ViewGroup的左上角為座標原點來測量的,所以第一個子View的高度應該為0。
        int curHeight = 0; //注意此處和上面錯誤的不一樣
        for (int i = 0 ; i < count ; i++){
            View childView = getChildAt(i);
            int height = childView.getMeasuredHeight();
            int width = childView.getMeasuredWidth();
            childView.layout(left,curHeight,right + width,bottom + height);

            curHeight += height;
        }
    }

上面的註釋寫的很清楚,是因為對ViewGroup中onLayout方法中的引數理解錯誤導致的,如果此處curHeight欄位填寫top引數,那麼ViewGroup中的第一個子View肯定會向下移動上面並列的View的高度。

參考文章:自定義View,有這一篇就夠了