一、自定義控件流程
onMeasure()? ----> onLayout? ------->onDraw()
每個(gè)view的繪制流程包含三個(gè)階段,一是測量過程,二是布局過程,三是繪制過程(展現(xiàn)在屏幕上)
1、頁面加載過程中,從最上層viewGroup開始,逐層向下遞歸,父布局調(diào)用子布局的measure()方法,measure()方法是一個(gè)調(diào)度方法,它會(huì)調(diào)用子View的onMeasure()方法,如果子View是ViewGroup,則依次向下遞歸調(diào)用子View的measure()方法,如果子View是View而不是ViewGroup,那么該子View會(huì)調(diào)用自己的onMeasure()方法,在方法中測量自己的寬高信息,然后交給父布局存儲下該子View的寬高信息。
2、接下來是父布局調(diào)用子布局的layout()方法,layout()方法時(shí)一個(gè)調(diào)度方法,它會(huì)調(diào)用子View的onLayout()方法,如果子View是ViewGroup,那么會(huì)依次遞歸調(diào)用子View的onLayout()方法,如果子View是View而不是ViewGroup,那么該子View會(huì)調(diào)用自己的onLayout()方法,在父布局調(diào)用子布局的layout時(shí)候,會(huì)將子View存在父布局的寬高信息傳遞給子View。
下面是一個(gè)自定義正方形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) {
? ? ? ? //使用這個(gè)方法的setMeasuredDimension()方法,將寬高設(shè)置進(jìn)去
? ? ? ? ? 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í)際寬高設(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ī)則傳遞給父布局。