自定义view学习笔记一:五角星绘制

刚开始学习自定义view,记录一下学习过程。
参考了网络上的一些博文,自定义view需要关注最多的就是3个方法:onMeasure(), onLayout(),onDraw(),而其中最关键的就是onDraw()方法了。而自定义view中我们需要做的就是在canvas上面通过paint来画出我们想要的图形,下面是画五角星的代码。

package com.leen.android.customviewtest;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import static java.lang.Math.PI;

public class AngleView extends View {
    private static String TAG = "AngleView";

    private int defaultWidth = 300;
    private int defaultHeight = 300;  //view的默认宽高
    private int mCenterX;
    private int mCenterY;  //view的中心点
    private int mBackgroudColor;
    private int mPaintColor;
    private int mRotation;  //五角星旋转角度

    private Paint mPaint;
    private Path mPath;

    public AngleView(Context context) {
        this(context, null);
    }

    public AngleView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AngleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mBackgroudColor = Color.RED;
        mPaintColor = Color.YELLOW;
        mRotation = 0;

        if(mPaint == null)
            mPaint = new Paint();

        if(mPath == null)
            mPath = new Path();

        //setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        //mPaint.setAntiAlias(true);
    }

    private int getMySize(int measureSpec, int defaultSize) {
        int mode = MeasureSpec.getMode(measureSpec);
        int size = MeasureSpec.getSize(measureSpec);

        Log.d(TAG, "defaultSize=" + defaultSize + ", mode=" + mode + ", size=" + size);
        switch (mode) {
            case MeasureSpec.AT_MOST:
            case MeasureSpec.UNSPECIFIED:
                return defaultSize;
            case MeasureSpec.EXACTLY:
                return size;
            default:
                return defaultSize;
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int width = getMySize(widthMeasureSpec, defaultWidth);
        int height = getMySize(heightMeasureSpec, defaultHeight);

        setMeasuredDimension(width, height);

        mCenterX = getMeasuredWidth() / 2;
        mCenterY = getMeasuredHeight() / 2;
        Log.d(TAG, "mCenterX=" + mCenterX + ", mCenterY=" + mCenterY);

        int r = getMeasuredWidth() / 3;  //五角星外接圆半径
        float angle = 72f;  //五个角对应的角度 360/5
        double rad = 2 * PI / 360;  //1度对应的弧度

        //五角星五个角顶点坐标算法:
        //x = r * cos(n * angle * rad)
        //y = r * sin(n * angle * rad)
        float a[] = {(float) (Math.cos(0 * angle * rad) * r), (float) (Math.sin(0 * angle * rad) * r)};
        float b[] = {(float) (Math.cos(1 * angle * rad) * r), (float) (-Math.sin(1 * angle * rad) * r)};
        float c[] = {(float) (Math.cos(2 * angle * rad) * r), (float) (-Math.sin(2 * angle * rad) * r)};
        float d[] = {(float) (Math.cos(3 * angle * rad) * r), (float) (-Math.sin(3 * angle * rad) * r)};
        float e[] = {(float) (Math.cos(4 * angle * rad) * r), (float) (-Math.sin(4 * angle * rad) * r)};

        mPath.moveTo(a[0], a[1]);
        mPath.lineTo(c[0], c[1]);
        mPath.lineTo(e[0], e[1]);
        mPath.lineTo(b[0], b[1]);
        mPath.lineTo(d[0], d[1]);
        mPath.close();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Log.d(TAG, "onDraw()");

        mPaint.setColor(mPaintColor);
        canvas.translate(mCenterX, mCenterY);  //将画布原点移动到view中心
        canvas.drawColor(mBackgroudColor);
        canvas.rotate(mRotation);  //旋转画布,顺时针为正,逆时针为负
        canvas.drawPath(mPath, mPaint);
    }

    public void setColor(int backgroudColor, int paintColor) {
        mBackgroudColor = backgroudColor;
        mPaintColor = paintColor;
        invalidate();
    }

    public void setRotate(int rotate) {
        mRotation = rotate;
        invalidate();
    }
}

代码算比较简单了,我的做法是确定好五角星的五个顶点坐标,然后连成线,再填充。这个过程中也遇到了一些问题,比较关键的就是五个顶点坐标的算法,还有原点坐标默认是左上角,需要做个位移。
效果图如下:
自定义view学习笔记一:五角星绘制