自定義View總結筆記
自定義View
自定義的構造方法:
例項程式碼1:
//程式碼中直接new出來的 public CakeView(Context context) { this(context,null); } //佈局中引用 public CakeView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } //佈局中應用,並且帶style(不常用) public CakeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { this(context, attrs); }
其中用的比較多的是一個引數和兩個引數的建構函式。兩個引數的建構函式的第二個引數AttributeSet是指這個自定義View的屬性值,就是下面程式碼中的layout_width,layout_height,defultSize等屬性。
例項程式碼2:
<com.example.CakeView
android:layout_width="200dp"
android:layout_height="200dp"
app:defultSize="200dp"/>
這些屬性可以通過obtainStyledAttributes()方法來獲取屬性值.
例項程式碼3:
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RecView);
defultSize = (int) typedArray.getDimension(R.styleable.RecView_defultSize, 200);
typedArray.recycle();
其中defultSize屬性是我自定義的屬性,自定義屬性在res--> values 目錄下新建一個命名為attrs的xml檔案。
例項程式碼4:
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="RecView" > <attr name="defultSize" format="dimension" /> </declare-styleable> </resources>
上述獲取屬性值的程式碼例項中,obtainStyledAttributes()方法獲取的是自定義View的屬性集,再通過getDimension(...)或getBoolean(...)方法獲取具體的自定義屬性。獲取完記得呼叫typedArray.recycle()回收資源,不然可能導致記憶體洩漏。
自定義View中重要的兩個重寫方法:onMeasure() 和 onDraw()介紹:
自定義View的流程是先測量(onMeasure() ),測量完成之後再繪製到螢幕上( onDraw() )
onMeasure()方法:view的測量,也就是測量View的寬高尺寸。
例項程式碼5:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWSize = getMySize(defultSize, widthMeasureSpec);
mHSize = getMySize(defultSize, heightMeasureSpec);
setMeasuredDimension(mWSize, mHSize);
}
public int getMySize(int defultSize, int measureSpec) {
int mSize = defultSize;
int size = MeasureSpec.getSize(measureSpec);
int mode = MeasureSpec.getMode(measureSpec);
switch (mode) {
case MeasureSpec.UNSPECIFIED:
break;
case MeasureSpec.AT_MOST:
mSize = defultSize;
break;
case MeasureSpec.EXACTLY:
mSize = size;
break;
}
return mSize;
}
其中onMeasure()方法中有兩個引數:widthMeasureSpec,heightMeasureSpec.這兩個引數是父控制元件傳遞給子view的測量要求,他們裡面包含父控制元件傳遞給子view的測量模式和父控制元件傳遞給子控制元件的測量值,而測量模式又分為三種,如上面的例項程式碼:
UNSPECIFIED:指子控制元件想要多大就多大,RecycleView和ListView,ScrollView就是這種模式。
AT_MOST:相當於wrap_content
EXACITLY:相當於match_parent 或者是固定尺寸,如:100dp
測量模式可以通過MeasureSpec.getMode()獲取,如上述程式碼例項。其中getSize()方法是父控制元件傳遞給子View的測量值,上述程式碼例項程式碼5的意思是:如果例項程式碼2中設定的寬高是固定200dp,或者是match_parent,此時view的父控制元件傳遞給子View的測量模式是EXACITLY,父控制元件傳遞給子view的測量值等於自己設定的寬高值(或者是推薦值),如果程式碼例項2中設定的寬高為wrap_content,此時父控制元件傳遞給子view的測量模式是ATM_MOST,測量值使用自己定義的預設值。測量完成之後一定要呼叫setMeasuredDimension(mWSize, mHSize)方法儲存測量值。
onDraw()方法:將測量完成的view繪製到螢幕上
例項程式碼6:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int r = getMeasuredWidth()/2;
//圓心的橫座標為控制元件的左邊起始位置加上半徑
int centerX = getLeft() + r;
int centerY = getTop() + r;
mPaint.setColor(Color.RED);
canvas.drawCircle(centerX,centerY,r,mPaint);
}
canvas是畫布,mPaint是畫筆,Paint最好在構造方法中建立,因為如果在onMeasure和onDraw方法都是頻繁的被呼叫。通過paint畫筆在canvas畫布上繪製你需要的圖形。