一析珊、自定義控件流程
onMeasure()? ----> onLayout? ------->onDraw()
每個view的繪制流程包含三個階段碘梢,一是測量過程州邢,二是布局過程杉武,三是繪制過程(展現(xiàn)在屏幕上)
1辙诞、頁面加載過程中,從最上層viewGroup開始轻抱,逐層向下遞歸飞涂,父布局調(diào)用子布局的measure()方法,measure()方法是一個調(diào)度方法,它會調(diào)用子View的onMeasure()方法较店,如果子View是ViewGroup志鹃,則依次向下遞歸調(diào)用子View的measure()方法,如果子View是View而不是ViewGroup泽西,那么該子View會調(diào)用自己的onMeasure()方法曹铃,在方法中測量自己的寬高信息,然后交給父布局存儲下該子View的寬高信息捧杉。
2陕见、接下來是父布局調(diào)用子布局的layout()方法,layout()方法時一個調(diào)度方法味抖,它會調(diào)用子View的onLayout()方法评甜,如果子View是ViewGroup,那么會依次遞歸調(diào)用子View的onLayout()方法仔涩,如果子View是View而不是ViewGroup忍坷,那么該子View會調(diào)用自己的onLayout()方法,在父布局調(diào)用子布局的layout時候熔脂,會將子View存在父布局的寬高信息傳遞給子View佩研。
下面是一個自定義正方形ImageView的例子:
public class SquareImageViewextends AppCompatImageView {
public SquareImageView(Context context) {
????this(context,null);
}
public SquareImageView(Context context, AttributeSet attrs) {
????????????super(context, attrs);
? ? }
@Override
?protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
? ? ? ? //使用這個方法的setMeasuredDimension()方法,將寬高設(shè)置進去
? ? ? ? ? super.onMeasure(widthMeasureSpec, heightMeasureSpec);
? ? ? ? ? //獲取設(shè)置的寬和高
? ? ? ? ? int measuredWidth = getMeasuredWidth();
? ? ? ? ? int measuredHeight = getMeasuredHeight();
? ? ? ? ? //定義自己的寬高設(shè)置方法
? ? ? ? ? if (measuredWidth > measuredHeight){
? ? ? ? ? ? ?measuredWidth=measuredHeight;
? ? ? ? ? ? }else {
? ? ? ? ? ? ?measuredHeight=measuredWidth;
? ? ? ? ? ? }
? ? ? //定義好寬高規(guī)則后霞揉,需要調(diào)用setMeasuredDimension()方法旬薯,將實際寬高設(shè)置給父布局
? ? ? ? setMeasuredDimension(measuredWidth,measuredHeight);
? ? }
}
在例子中,重寫onMeasure()方法适秩,需要先調(diào)用?super.onMeasure(widthMeasureSpec, heightMeasureSpec);方法绊序,觸發(fā)父類的setMeasuredDimension方法,得到測量的寬高秽荞,然后調(diào)用getMeasuredWidth骤公、getMeasuredHeight方法,來獲取通過setMeasuredDimension方法設(shè)置好的寬高信息扬跋,然后接下來就是定義自己的寬高規(guī)則阶捆,最后一步很重要,需要調(diào)用setMeasuredDimension()方法胁住,將設(shè)置好的寬高規(guī)則傳遞給父布局趁猴。