坐標系說明:
View的坐標系:
實現(xiàn)流程:
主要方法onMeasure()植阴、onLayout()盖呼、onDraw();
1、View的構(gòu)造方法的重載
public class MyView extends View {
private String TAG="MyView";
//重載View的構(gòu)造函數(shù)
//一般在直接New一個View的時候調(diào)用
public MyView(Context context) {
super(context);
Log.d(TAG,"======MyView1");
}
//一般在layout文件中使用的時候會調(diào)用,關(guān)于它的所有屬性(包括自定義屬性)都會包含在attrs中傳遞進來。
public MyView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
Log.d(TAG,"======MyView2");
}
//由于三個參數(shù)的構(gòu)造函數(shù)第三個參數(shù)一般不用,暫不考慮
public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
Log.d(TAG,"======MyView3");
}
//有四個參數(shù)的構(gòu)造函數(shù)在API21的時候才添加上,暫不考慮
/*public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.d(TAG,"======onDraw");
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
Log.d(TAG,"======onLayout");
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Log.d(TAG,"======onMeasure");
}
}
在布局文件中引用當前view:
<com.wtt.testac.custom.MyView
android:layout_width="match_parent"
android:layout_height="match_parent" />
打印的結(jié)果:
結(jié)論:在布局文件中調(diào)用的構(gòu)造方法是兩個參數(shù)的構(gòu)造方法终惑。為什么方法會被多次調(diào)用?因為view繪制過程中為了確認view大小声登,會多次重復(fù)調(diào)用onMeasure狠鸳。
2揣苏、構(gòu)造方法接下來調(diào)用onMeasure()方法來測量View的大小
View的大小不僅由自身所決定,同時也會受到父控件的影響件舵,為了我們的控件能更好的適應(yīng)各種情況卸察,一般會自己進行測量。
//計算view高度寬度大小
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Log.d(TAG,"======onMeasure");
//測量View大小
int width=MeasureSpec.getSize(widthMeasureSpec);//測量寬度的大小
int width_mode=MeasureSpec.getMode(widthMeasureSpec);//取出寬度的測量模式
Log.d(TAG,"width==="+width);
Log.d(TAG,"width_mode==="+width_mode);
int height=MeasureSpec.getSize(heightMeasureSpec);//測量高度的大小
int height_mode=MeasureSpec.getMode(heightMeasureSpec);//取出高度的測量模式
Log.d(TAG,"height==="+height);
Log.d(TAG,"height_mode==="+height_mode);
}
從上面可以看出 onMeasure 函數(shù)中有 widthMeasureSpec 和 heightMeasureSpec 這兩個 int 類型的參數(shù)铅祸,它們是和寬高相關(guān)的坑质, 但它們其實不是寬和高, 而是由寬临梗、高和各自方向上對應(yīng)的測量模式來合成的一個值涡扼。
在MeasureSpec當中一共存在三種mode:UNSPECIFIED、EXACTLY 和AT_MOST盟庞。
在測量之后吃沪,View的大小已經(jīng)確定,View的大小不僅由自身控制還受父布局的影響什猖,所以可以調(diào)用onSizeChanged()函數(shù)來確定View的大小票彪。
//函數(shù)在視圖大小發(fā)生改變時調(diào)用
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//參數(shù)分別是寬、高不狮、上一次寬降铸、上一次高
}
3、調(diào)用onLayout()函數(shù)來設(shè)置View的位置摇零,一般情況下是在VIewGroup中會調(diào)用到推掸,調(diào)用了子View中的layout()函數(shù)。
在自定義ViewGroup中驻仅,onLayout一般是循環(huán)取出子View谅畅,然后經(jīng)過計算得出各個子View位置的坐標值。
//計算view位置
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
Log.d(TAG,"======onLayout");
//left View左側(cè)距父View左側(cè)的距離
//top View頂部距父View頂部的距離
//right View右側(cè)距父View左側(cè)的距離
//bottom View底部距父View頂部的距離
}
4雾家、調(diào)用onDraw()函數(shù)繪制VIew
在onDraw()方法中有一個Canvas對象铃彰,稱之為畫布,可以在上面繪制各種東西芯咧。
//繪制View
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.d(TAG,"======onDraw");
//繪制顏色
canvas.drawColor(Color.YELLOW);
}
想要繪制內(nèi)容,需要一個Paint畫筆竹揍,然后就可以在Canvas畫布上繪制任何VIew了
//創(chuàng)建畫筆
Paint paint=new Paint();
//在構(gòu)造方法中調(diào)用方法
private void init(){
paint.setColor(Color.BLACK);//設(shè)置畫筆顏色
paint.setStyle(Paint.Style.STROKE);//設(shè)置畫筆為空心
paint.setStrokeWidth(5f);//設(shè)置畫筆寬度
}
繪制一個圓環(huán):
//cx圓心x坐標敬飒、cy圓心y坐標、radius半徑芬位、paint畫筆
canvas.drawCircle(150f,150f,50f,paint);
繪制矩形的幾種方法:
// 第一種
canvas.drawRect(100,100,500,300,paint);
// 第二種
Rect rect = new Rect(100,100,500,300);
canvas.drawRect(rect,paint);
// 第三種
RectF rectF = new RectF(100,100,500,300);
canvas.drawRect(rectF,paint);
這幾種方法繪制出來的View都是是一樣的无拗,Rect和RectF有什么區(qū)別呢,兩者最大的區(qū)別是精度不同昧碉,Rect是int(整形)的英染,而RectF是float(單精度浮點型)的揽惹。
總結(jié):以上是自定義view的基礎(chǔ)的相關(guān)的內(nèi)容,很多東西還是得自己親自手敲實踐四康,腳踏實地走過來才行搪搏。以后還會繼續(xù)完善本文的內(nèi)容,有不對的地方闪金,歡迎指出疯溺,會繼續(xù)努力。