1. 程式人生 > >自定義View總結筆記

自定義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畫布上繪製你需要的圖形。