自定義view初探(一)

初次自定義view,繪製了一個表,點擊錶針會轉動。自定義的控件的儘量將可以從外部設置的屬性暴露出來,這樣增加控件適用場合和靈活性。

思路

  • extends view並實現其中的onDraw方法來實現繪製圖形
  • 重寫其中的ClockView(Context context, AttributeSet attrs)來實現在xml中的引用
  • implements View.OnClickListener來實現監聽點擊
  • 重寫onSizeChanged方法實現部分參數的初始化和對界面尺寸變化的適應

參數說明

    private int count_clicked=0;//點擊次數
    private float mborderwidth;//畫筆寬度
    private int mbordercolor;//線條顏色

    private Paint mPaint;//畫筆
    private RectF mBounds;//矩形
    private float mWidth;//矩形區寬度
    private float mHeight;//矩形區高度
    private float mRadius;//指針半徑
    private float smalllength;//小刻度長
    private float largerlength;//大刻度長

1.創建一個ClockView繼承自view並實現View.OnClickListener方法,一定要記得重載其中的第二個構造器,這樣才能在xml中引用

public class ClockView extends View implements View.OnClickListener 

 public ClockView(Context context) 
 public ClockView(Context context, AttributeSet attrs)
 public ClockView(Context context, AttributeSet attrs, int defStyleAttr) 

2.爲了在xml中設置屬性,爲控件設置屬性,在values下創建attrs.xml文件

<resources>
    <declare-styleable name="ClockView">
        <attr name="border_color" format="color"/>
        <attr name="border_width" format="dimension"/>
    </declare-styleable>
</resources>

3.重寫構造方法,從xml中解析屬性,初始化一些數據

public ClockView(Context context, AttributeSet attrs) {
        super(context, attrs);

        //獲取xml中的自定義屬性
        TypedArray typedArray=context.getTheme().obtainStyledAttributes(
                attrs,R.styleable.ClockView,0,0);  
                mbordercolor=typedArray.getColor(R.styleable.ClockView_border_color,0xff000000); 
                   mborderwidth=typedArray.getDimension(R.styleable.ClockView_border_width, 2);

    InitPara();
    setOnClickListener(this);
    }

4.初始化畫筆並處理點擊事件,每次點擊旋轉6度,一共可以旋轉60次,count_clicked記錄需要旋轉的次數(在每個構造器中添加InitPara(); setOnClickListener(this);)

private void InitPara(){
        mPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(mborderwidth);
        mPaint.setColor(mbordercolor);
    }
 @Override
 public void onClick(View v) {
        count_clicked++;//控制錶針的轉動位置
        if(count_clicked%60==0){
            count_clicked=0;
        }
        invalidate();//重新繪製,調用onDraw
    }    

5.重寫onSizeChanged,並進行一些數據初始化

/**
     * 當界面的尺寸發生改變時調用
     * @param w
     * @param h
     * @param oldw
     * @param oldh
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        mBounds=new RectF(getLeft(),getTop(),getRight(),getBottom());
        mWidth=mBounds.right-mBounds.left;
        mHeight=mBounds.bottom-mBounds.top;
        if(mHeight<mWidth){
            mRadius=mHeight/4;
        }else{
            mRadius=mWidth/4;
        }

        smalllength=30;
        largerlength=60;
    }

6.自定義ClockDraw(canvas, count_clicked)用來繪製自定義的圖形

private void ClockDraw(Canvas canvas,int count){
        //繪製底色和矩形框
        canvas.drawColor(0xff000000);
        canvas.drawRoundRect(new RectF(mBounds.centerX()-(float)0.9*mWidth/2,
                mBounds.centerY() - (float)0.9*mHeight/2,
                mBounds.centerX() + (float)0.9*mWidth/2,
                mBounds.centerY() + (float)0.9*mHeight/2), 30, 30, mPaint);
        mPaint.setColor(mbordercolor);
        //繪製錶盤的刻度
        float start_x,start_y;
        float end_x,end_y;
        for(int i=0;i<60;i++)
        {
            start_x=mRadius*(float)Math.cos(Math.PI / 180 * i * 6);
            start_y=mRadius*(float)Math.sin(Math.PI/180*i*6);
            if(i%5==0){
                end_x=(mRadius+largerlength)*(float)Math.cos(Math.PI / 180 * i * 6);
                end_y=(mRadius+largerlength)*(float)Math.sin(Math.PI/180*i*6);
            }else {
                end_x=(mRadius+smalllength)*(float)Math.cos(Math.PI / 180 * i * 6);
                end_y=(mRadius+smalllength)*(float)Math.sin(Math.PI/180*i*6);
            }
            start_x+=mBounds.centerX();
            start_y+=mBounds.centerY();
            end_x+=mBounds.centerX();
            end_y+=mBounds.centerY();
            canvas.drawLine(start_x,start_y,end_x,end_y,mPaint);
        }
        canvas.drawCircle(mBounds.centerX(), mBounds.centerY(), mRadius, mPaint);//錶盤的圓
        canvas.drawCircle(mBounds.centerX(), mBounds.centerY(), 20, mPaint);//表芯的圓
        canvas.rotate(6 * count, mBounds.centerX(), mBounds.centerY());//旋轉畫布,座標系跟隨畫布旋轉
        canvas.drawLine(mBounds.centerX(), mBounds.centerY(), mBounds.centerX(), mBounds.centerY() - mRadius, mPaint);
    }

7.重寫onDraw方法,調用自己的Draw方法

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        ClockDraw(canvas, count_clicked);
    }

在xml中調用自定義的view,設置顏色和線條粗細

<com.demo.eric.defineview.ClockView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:border_color="#eaf1e90b"
        app:border_width="4dp"/>

完成!!!

未點擊
點擊後

總結:

重點是onDraw中的重寫,在onDraw中進行一系列的圖形繪製;canvas作爲畫布,利用paint在canvas上調用canvas.drawXXX(X,X,X,……,paint)繪製自己想要的圖形。

ClockView整體源碼

/**
 * Created by Administrator on 2016/1/7 0007.
 */
public class ClockView extends View implements View.OnClickListener {

    private int count_clicked=0;//點擊次數
    private float mborderwidth;//畫筆寬度
    private int mbordercolor;//線條顏色

    private Paint mPaint;//畫筆
    private RectF mBounds;//矩形
    private float mWidth;//矩形區寬度
    private float mHeight;//矩形區高度
    private float mRadius;//指針半徑
    private float smalllength;//小刻度長
    private float largerlength;//大刻度長


    public ClockView(Context context) {
        super(context);
        setOnClickListener(this);
        InitPara();
    }

    public ClockView(Context context, AttributeSet attrs) {
        super(context, attrs);

        //獲取xml中的自定義屬性
        TypedArray typedArray=context.getTheme().obtainStyledAttributes(
                attrs,R.styleable.ClockView,0,0);

        mbordercolor=typedArray.getColor(R.styleable.ClockView_border_color,0xff000000);
        mborderwidth=typedArray.getDimension(R.styleable.ClockView_border_width, 2);
        InitPara();
        setOnClickListener(this);
    }

    public ClockView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        InitPara();
        setOnClickListener(this);
    }

    private void InitPara(){
        mPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(mborderwidth);
        mPaint.setColor(mbordercolor);
    }

    /**
     * 當界面的尺寸發生改變時調用
     * @param w
     * @param h
     * @param oldw
     * @param oldh
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        mBounds=new RectF(getLeft(),getTop(),getRight(),getBottom());
        mWidth=mBounds.right-mBounds.left;
        mHeight=mBounds.bottom-mBounds.top;
        if(mHeight<mWidth){
            mRadius=mHeight/4;
        }else{
            mRadius=mWidth/4;
        }

        smalllength=30;
        largerlength=60;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        ClockDraw(canvas, count_clicked);
    }

    private void ClockDraw(Canvas canvas,int count){
        //繪製底色和矩形框
        canvas.drawColor(0xff000000);
        canvas.drawRoundRect(new RectF(mBounds.centerX()-(float)0.9*mWidth/2,
                mBounds.centerY() - (float)0.9*mHeight/2,
                mBounds.centerX() + (float)0.9*mWidth/2,
                mBounds.centerY() + (float)0.9*mHeight/2), 30, 30, mPaint);
        mPaint.setColor(mbordercolor);
        //繪製錶盤的刻度
        float start_x,start_y;
        float end_x,end_y;
        for(int i=0;i<60;i++)
        {
            start_x=mRadius*(float)Math.cos(Math.PI / 180 * i * 6);
            start_y=mRadius*(float)Math.sin(Math.PI/180*i*6);
            if(i%5==0){
                end_x=(mRadius+largerlength)*(float)Math.cos(Math.PI / 180 * i * 6);
                end_y=(mRadius+largerlength)*(float)Math.sin(Math.PI/180*i*6);
            }else {
                end_x=(mRadius+smalllength)*(float)Math.cos(Math.PI / 180 * i * 6);
                end_y=(mRadius+smalllength)*(float)Math.sin(Math.PI/180*i*6);
            }
            start_x+=mBounds.centerX();
            start_y+=mBounds.centerY();
            end_x+=mBounds.centerX();
            end_y+=mBounds.centerY();
            canvas.drawLine(start_x,start_y,end_x,end_y,mPaint);
        }
        canvas.drawCircle(mBounds.centerX(), mBounds.centerY(), mRadius, mPaint);//錶盤的圓
        canvas.drawCircle(mBounds.centerX(), mBounds.centerY(), 20, mPaint);//表芯的圓
        canvas.rotate(6 * count, mBounds.centerX(), mBounds.centerY());//旋轉畫布,座標系跟隨畫布旋轉
        canvas.drawLine(mBounds.centerX(), mBounds.centerY(), mBounds.centerX(), mBounds.centerY() - mRadius, mPaint);

    }

    @Override
    public void onClick(View v) {
        count_clicked++;
        if(count_clicked%60==0){
            count_clicked=0;
        }
        invalidate();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章