Android自定义View七(复习基本图形的绘制)

基本图形的绘制


public class CanvasLearn extends View {
    private Paint mPaint;

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

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

    public CanvasLearn(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initPaint();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        setCanvasColor(canvas);
//        drawPoint(canvas);
//        drawLine(canvas);
//        drawRectOrRectF(canvas);
//        drawRoundRect(canvas);
//        drawOval( canvas);
//        drawCircle(canvas);
//        drawAre(canvas);
    }

    /**
     * 1、初始化画笔
     */
    private void initPaint() {
        mPaint = new Paint();
        mPaint.setStrokeWidth(10);//设置画笔宽度
        mPaint.setColor(Color.RED);//设置画笔颜色
        mPaint.setStyle(Paint.Style.FILL);//设置画布类型(Fill填充STROKE扫边 FILL_AND_STROKE填充和扫边)

    }

    /**
     * 2、设置画布颜色
     */
    private void setCanvasColor(Canvas canvas) {
        canvas.drawColor(Color.WHITE);
    }

    /**
     * 3、绘制点及多个点
     */
    private void drawPoint(Canvas canvas) {
        mPaint.setStrokeCap(Paint.Cap.ROUND);//设置圆角触笔是点变成圆点
        mPaint.setColor(Color.BLUE);
        canvas.drawPoint(100, 100, mPaint);//绘制一个点
        mPaint.setColor(Color.GREEN);//设置画笔颜色区分
        canvas.drawPoints(new float[]{500, 200, 500, 400, 500, 600}, mPaint);//根据多个坐标绘制多个点
    }

    /**
     * 4、绘制直线及多个线段
     */
    private void drawLine(Canvas canvas) {
        mPaint.setColor(Color.BLUE);
        canvas.drawLine(100, 100, 300, 100, mPaint);//绘制一条线段(参数是其实点到x、y轴坐标到结束到x、y轴坐标)
        mPaint.setColor(Color.GREEN);//设置画笔颜色区分
        canvas.drawLines(new float[]{200, 200, 300, 200, 200, 400, 500, 400}, mPaint);
    }

    /**
     * 5、绘制矩形
     * Rect与RectF的区别是精度不同,Rect是int型,Rect是float型
     */
    private void drawRectOrRectF(Canvas canvas) {
        //第一种
        canvas.drawRect(100, 100, 800, 200, mPaint);
        //第二种
        Rect rect = new Rect(100, 300, 800, 400);
        canvas.drawRect(rect, mPaint);
        //第三种
        RectF rectF = new RectF(100, 500, 800, 600);
        canvas.drawRect(rectF, mPaint);
    }

    /**
     * 绘制圆角矩形
     */
    private void drawRoundRect(Canvas canvas) {
        //第一种
        RectF rectF = new RectF(100, 100, 800, 400);
        canvas.drawRoundRect(rectF, 30, 30, mPaint);
        //第二种方法在API21的时候才可以用,建议用第一种
        //设置圆弧角度rx>矩形宽度/2(350)  ry>矩形高度/2 (200)时都可以画成椭圆
        canvas.drawRect(100,600,800,1000,mPaint);
        mPaint.setColor(Color.GRAY);
        canvas.drawRoundRect(100,600,800,1000,350,250,mPaint);
    }

    /**
     * 绘制椭圆
     */
    private void drawOval(Canvas canvas){
        //第一种
        RectF rectF=new RectF(100,100,800,400);
        canvas.drawOval(rectF,mPaint);
        //第二种不建议使用21以上才有
        canvas.drawOval(100,500,800,900,mPaint);
    }

    /**
     *  绘制一个圆心坐标在(500,500),半径为300 的圆
     */
    private void drawCircle(Canvas canvas){
        canvas.drawCircle(500,500,300,mPaint);
    }
    /**
     * 绘制圆弧
     * 参数先容startAngle 开始角度 sweepAngle 结束角度  useCenter 是否使用中心
     */
    private void drawAre(Canvas canvas){
        RectF rectF=new RectF(100,100,500,500);
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(rectF,mPaint);
        mPaint.setColor(Color.GREEN);
        canvas.drawArc(rectF,0,90,false,mPaint);

        RectF rectF1=new RectF(100,600,500,1100);
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(rectF1,mPaint);
        mPaint.setColor(Color.GREEN);
        canvas.drawArc(rectF1,0,90,true,mPaint);
    }

简单的绘制一个圆饼图

public class PieView extends View {
    private int[] datas = {20, 60, 80, 10, 50};//数据
    private int[] colors = {Color.BLACK, Color.GREEN, Color.GRAY, Color.RED, Color.BLUE};//颜色
    private int mWidth, mHeight; //宽高
    private float mRadius;    //半径
    private RectF rectF;//圆饼图区域
    private Paint mPaint = new Paint();//画笔

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

    public PieView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public PieView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setAntiAlias(true);
    }
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mHeight = h;
        mWidth = w;
        mRadius = Math.min(mHeight, mWidth) / 2 * 0.8f;
        rectF = new RectF(-mRadius, -mRadius, mRadius, mRadius);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.translate(mWidth / 2, mHeight / 2);
        drawPie(canvas);
    }
    /**
     *绘制圆饼图
     */
    private void drawPie(Canvas canvas) {
        float sumValues = 0;
        for (int i = 0; i < datas.length; i++) {
            sumValues += datas[i];
        }
        float startAngle = 0;//初始角度
        for (int i = 0; i < datas.length; i++) {
            mPaint.setColor(colors[i]);
            float percentage = datas[i] / sumValues ;
            float angle=percentage*360;
            canvas.drawArc(rectF,startAngle,angle,true,mPaint);
            startAngle += angle;
        }
    }
}
Screenshot_1489053291.png

根据Path图形的绘制


public class PathLearn extends View {
    private Paint mPaint;
    private int mWidth, mHeight;

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

    public PathLearn(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public PathLearn(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    private void initView() {
        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(Color.GREEN);
        mPaint.setAntiAlias(true);
        mPaint.setStrokeWidth(10);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.translate(mWidth / 2, mHeight / 2);
//        canvas.scale(1,-1);//翻转y轴坐标
        drawAllPoint(canvas);
        drawPathXY(canvas);
//        drawPathLine(canvas);
//        drawPathRect(canvas);
//        drawPathAll(canvas);
//        drawPathaddArc(canvas);

    }
    //------------moveTo、 setLastPoint、 lineTo 和 close-----------------

    /**
     * 利用path绘制坐标和箭头
     * moveTo  设置path起点
     * lineTo  path直线到终点
     */
    private void drawPathXY(Canvas canvas) {
        Path mPath = new Path();
        mPaint.setStrokeWidth(1);
        mPaint.setColor(Color.BLACK);
        mPaint.setStyle(Paint.Style.STROKE);
        //x轴与箭头
        mPath.moveTo(-mWidth / 2 * 0.8f, 0);
        mPath.lineTo(mWidth / 2 * 0.8f, 0);

        mPath.lineTo(mWidth / 2 * 0.8f * 0.95f, -mWidth / 2 * 0.8f * 0.05f);
        mPath.moveTo(mWidth / 2 * 0.8f, 0);
        mPath.lineTo(mWidth / 2 * 0.8f * 0.95f, mWidth / 2 * 0.8f * 0.05f);

        //y轴
        mPath.moveTo(0, -mHeight / 2 * 0.8f);
        mPath.lineTo(0, mHeight / 2 * 0.8f);
        //y轴箭头
        mPath.moveTo(mWidth / 2 * 0.8f * 0.05f, mHeight / 2 * 0.8f - mWidth / 2 * 0.8f * 0.05f);
        mPath.lineTo(0, mHeight / 2 * 0.8f);
        mPath.lineTo(-mWidth / 2 * 0.8f * 0.05f, mHeight / 2 * 0.8f - mWidth / 2 * 0.8f * 0.05f);
        canvas.drawPath(mPath, mPaint);
    }

    /**
     * setLastPoint() 重置上一次操作的最后一个点
     * close() 方法用于连接当前最后一个点和最初的一个点
     */
    private void drawPathLine(Canvas canvas) {
        Path mPath = new Path();
        mPaint.setColor(Color.RED);
        mPaint.setStrokeWidth(5);
        mPath.lineTo(200, 200);
//        mPath.moveTo(200,100);
        mPath.setLastPoint(200, 100);
        mPath.lineTo(200, 0);
        mPath.close();
        canvas.drawPath(mPath, mPaint);
    }

    /**
     * 用原点和四个端点
     */

    private void drawAllPoint(Canvas canvas) {
        mPaint.setStrokeWidth(20);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        canvas.drawPoints(new float[]{0, 0, mWidth / 2 * 0.8f, 0, -mWidth / 2 * 0.8f, 0, 0, mHeight / 2 * 0.8f, 0, -mHeight / 2 * 0.8f}, mPaint);
    }

    //------------addCircle() addOval() addRect() addRoundRect()  参数Path.Direction  cw  顺时针  ccw 逆时针-----------------

    /**
     * path绘制矩形
     * setLastPoint(-300,300)修改最后点的位置
     */
    private void drawPathRect(Canvas canvas) {
        Path path = new Path();
//        path.addRect(-200, -200, 200, 200, Path.Direction.CW);
        path.addRect(-200, -200, 200, 200, Path.Direction.CCW);
//        path.setLastPoint(-300,300);
        canvas.drawPath(path, mPaint);
    }

    /**
     * patn绘制其他基本图形
     * addPath (Path src)将两个Path合并成为一个
     * addPath (Path src, float dx, float dy) 进行了位移之后再添加进当前path中
     * addPath (Path src, Matrix matrix) 添加到当前path之前先使用Matrix进行变换
     */
    private void drawPathAll(Canvas canvas) {
        Path path = new Path();
        Path path1 = new Path();
        Path path2 = new Path();
//        mPaint.setStyle(Paint.Style.FILL);
        path.addCircle(0, 0, 200, Path.Direction.CW);
//        path.setLastPoint(-300,300);
        path1.addOval(-300, -200, 300, 200, Path.Direction.CW);
//        path.setLastPoint(-300,300);
        path2.addRoundRect(-200, -200, 200, 200, 30, 30, Path.Direction.CW);
//        path.setLastPoint(-300,300);
        path.addPath(path1, 0, -300);
        path.addPath(path2, 0, 300);
        canvas.drawPath(path, mPaint);
    }

    //------------addArc与arcTo-----------------
    /**
     * public void addArc (RectF oval, float startAngle, float sweepAngle)
     * public void arcTo (RectF oval, float startAngle, float sweepAngle)
     * public void arcTo (RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)
     * oval  圆弧的外切矩形。
     * startAngle 开始角度
     * sweepAngle 扫过角度(-360 <= sweepAngle <360)
     * forceMoveTo  是否强制使用MoveTo
     * addArc  直接添加一个圆弧到path中
     * arcTo  添加一个圆弧到path,如果圆弧的起点和上次最后一个坐标点不相同,就连接两个点
     * forceMoveTo true 将最后一个点移动到圆弧起点,即不连接最后一个点与圆弧起点
     * firceMoveTo false 不移动,而是连接最后一个点与圆弧起点
     */

    /**
     * 圆弧
     */
    private void drawPathaddArc(Canvas canvas) {
        Path path = new Path();
        path.lineTo(100, -100);
        RectF rectF = new RectF(0, -200, 200, 0);
//        path.addArc(rectF,0,280);
//        path.arcTo(rectF,0,270,false);
        path.arcTo(rectF, 0, 270, true);
        path.offset(0,300,path);
        canvas.drawPath(path, mPaint);
    }
    //------------isEmpty、 isRect、isConvex、 set 和 offset-----------------
    /**
     * isEmpty() 判断path中是否包含内容 true-无内容  false-有内容
     * isRect()  判断path是否是一个矩形,如果是一个矩形的话,会将矩形的信息存放进参数rect中
     * set()     将新的path赋值到现有path
     * offset()  就是对path进行一段平移
     */

雷达图的绘制


public class RadarView extends View {

    private int count = 8;//数据个数
    private float angle = (float) (Math.PI * 2 / count);//每个数据的平均弧度
    private float radius;   //网络最大半径
    private int centerX;    //中心X坐标
    private int centerY;    //中心Y坐标
    private String[] titles = {"1", "2", "3", "4", "5", "6","7","8"};
    private double[] data = {20, 30, 40, 50, 60, 70,80,90}; //各维度分值
    private float maxValues = 100;    //数据最大值
    private Paint radarPaint = new Paint();       //雷达图画笔
    private Paint valuePaint = new Paint();       //网格图画笔
    private Paint textPaint = new Paint();        //文本画笔
    private Paint xyPaint = new Paint();           //坐标画笔
    private int mWidth, mHeight;



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

    public RadarView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RadarView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }


    //初始化数据
    private void initView() {
        //设置雷达画笔属性
        radarPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        radarPaint.setColor(Color.GREEN);
        radarPaint.setAntiAlias(true);
        //设置网格图画笔属性
        valuePaint.setStyle(Paint.Style.STROKE);
        valuePaint.setColor(Color.BLUE);
        valuePaint.setAntiAlias(true);
        //设置文本画笔属性
        textPaint.setStyle(Paint.Style.FILL);
        textPaint.setColor(Color.BLACK);
        textPaint.setTextSize(30);
        textPaint.setAntiAlias(true);
        //设置坐标画笔属性
        xyPaint.setColor(Color.RED);
        xyPaint.setAntiAlias(true);
        xyPaint.setStyle(Paint.Style.STROKE);
        xyPaint.setStrokeWidth(4);


    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;
        radius = Math.min(mWidth, mHeight) / 2 * 0.8f;
        centerY = h / 2;
        centerX = w / 2;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.translate(centerX, centerY);
//        drawXY(canvas);
        drawValues(canvas);
        drawCover(canvas);
    }

    /**
     * 画坐标
     */
    private void drawXY(Canvas canvas) {
        Path mPath = new Path();
        //x轴与箭头
        mPath.moveTo(-mWidth / 2 * 0.95f, 0);
        mPath.lineTo(mWidth / 2 * 0.95f, 0);

        mPath.lineTo(mWidth / 2 * 0.95f * 0.95f, -mWidth / 2 * 0.95f * 0.05f);
        mPath.moveTo(mWidth / 2 * 0.95f, 0);
        mPath.lineTo(mWidth / 2 * 0.95f * 0.95f, mWidth / 2 * 0.95f * 0.05f);

        //y轴
        mPath.moveTo(0, -mHeight / 2 * 0.95f);
        mPath.lineTo(0, mHeight / 2 * 0.95f);
        //y轴箭头
        mPath.moveTo(mWidth / 2 * 0.95f * 0.05f, mHeight / 2 * 0.95f - mWidth / 2 * 0.95f * 0.05f);
        mPath.lineTo(0, mHeight / 2 * 0.95f);
        mPath.lineTo(-mWidth / 2 * 0.95f * 0.05f, mHeight / 2 * 0.95f - mWidth / 2 * 0.95f * 0.05f);
        canvas.drawPath(mPath, xyPaint);
    }

    /**
     * 绘制网格图和文本
     */
    private void drawValues(Canvas canvas) {
        Path path = new Path();//多边形path
        Path linePath = new Path();//直线Path
        float r = radius / count - 1;//设置网格之间的间距
        Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
        float textHeight = (-fontMetrics.ascent - fontMetrics.descent);//文本高度
        for (int j = 0; j < count; j++) {
            float newR = r * j;
            path.reset();
            for (int i = 0; i < count; i++) {
                float x = (float) (newR * Math.cos(angle * i));
                float y = (float) (newR * Math.sin(angle * i));
                if(j==count-1){
                    //绘制直线
                    linePath.reset();
                    linePath.moveTo(0, 0);
                    linePath.lineTo(x, y);
                    canvas.drawPath(linePath, valuePaint);
                }
                if (i == 0) {
                    path.moveTo(newR, 0);
                } else {
                    path.lineTo(x, y);
                }
            }
            path.close();
            canvas.drawPath(path, valuePaint);

            //绘制文本
            float textX = (float) ((radius - r + textHeight / 2) * Math.cos(angle * j));
            float textY = (float) ((radius - r + textHeight / 2) * Math.sin(angle * j));
            float textWidth = textPaint.measureText(titles[j]);//文本长度

            if (j == 0) {
                canvas.drawText(titles[j], textX, textY + textHeight / 2, textPaint);
            } else if (j == 1) {
                canvas.drawText(titles[j], textX - textWidth / 2, textY + textHeight, textPaint);
            } else if (j == 2) {
                canvas.drawText(titles[j], textX - textWidth / 2, textY + textHeight, textPaint);
            } else if (j == 3) {
                canvas.drawText(titles[j], textX - textWidth, textY + textHeight / 2, textPaint);
            } else if (j == 4) {
                canvas.drawText(titles[j], textX - textWidth / 2, textY, textPaint);
            } else {
                canvas.drawText(titles[j], textX - textWidth / 2, textY, textPaint);
            }
        }
    }

        /**
         * 绘制覆盖区域
         */

    private void drawCover(Canvas canvas) {
        Path path=new Path();
        float r = radius / count - 1;//设置网格之间的间距
        for(int i=0;i<count;i++){
            double percent=data[i]/maxValues;
            float x = (float) ((radius-r)*Math.cos(angle*i)*percent);
            float y = (float) ((radius-r)*Math.sin(angle*i)*percent);
            if(i==0){
                path.moveTo(x,0);
            }else{
                path.lineTo(x,y);
            }
            //绘制小圆点
            canvas.drawCircle(x,y,5,radarPaint);
//            canvas.drawPoint(x,y,radarPaint);
        }
        path.close();
        radarPaint.setStyle(Paint.Style.STROKE);
        canvas.drawPath(path,radarPaint);
        //绘制填充区域
        radarPaint.setAlpha(105);
        radarPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        canvas.drawPath(path,radarPaint);
    }


}


效果

Screenshot_1489048128.png
Screenshot_1489049585.png
/**
     * 根据path绘制饼图
     */
    private void drawPathAcr(Canvas canvas) {
        float outRadius = mRadius;
        outRecF = new RectF(-outRadius, -outRadius, outRadius, outRadius);
        float alphaRadius = mRadius * 0.6f;
        alphaRecf = new RectF(-alphaRadius, -alphaRadius, alphaRadius, alphaRadius);
        float inRadius = mRadius * 0.5f;
        inRecF = new RectF(-inRadius, -inRadius, inRadius, inRadius);

        if (mDatas.size() == 0) {
            return;
        }
        canvas.rotate(drawStartAngle);
        canvas.save();
        float startAngle = 0;
        for (PieChartBean ben : mDatas) {
            float sweepAngle = ben.getPercentage();
            outPaht.moveTo(0, 0);
            outPaht.arcTo(outRecF, startAngle, sweepAngle);
            inPaht.moveTo(0, 0);
            inPaht.arcTo(inRecF, startAngle, sweepAngle);
            alphaPaht.moveTo(0, 0);
            alphaPaht.arcTo(alphaRecf, startAngle, sweepAngle);
            pietPaht.op(outPaht, inPaht, Path.Op.DIFFERENCE);
            alphaPiePaht.op(alphaPaht, inPaht, Path.Op.DIFFERENCE);
            arcPaint.setColor(ben.getPieColor());
            canvas.drawPath(pietPaht, arcPaint);
            arcPaint.setAlpha(100);
            arcPaint.setColor(Color.GRAY);
            canvas.drawPath(alphaPiePaht, arcPaint);
            outPaht.reset();
            inPaht.reset();
            alphaPaht.reset();
            startAngle += sweepAngle;
        }
    }

推荐阅读更多精彩内容