安卓自定义View-Canvas之绘制图形

来源:互联网 发布:佳能mg3580 清零软件 编辑:程序博客网 时间:2024/05/16 04:43

一.Canvas简介

Canvas我们可以称之为画布,能够在上面绘制各种东西,是安卓平台2D图形绘制的基础,非常强大。

一般来说,比较基础的东西有两大特点:

1.可操作性强:由于这些是构成上层的基础,所以可操作性必然十分强大。
2.比较难用:各种方法太过基础,想要完美的将这些操作组合起来有一定难度。
不过不必担心,本系列文章不仅会介绍到Canvas的操作方法,还会简单介绍一些设计思路和技巧。

二.Canvas的常用操作速查表

这里写图片描述

三.Canvas详解

绘制颜色:

绘制颜色是填充整个画布,常用于绘制底色。

canvas.drawColor(Color.BLUE); //绘制蓝色

创建画笔:
要想绘制内容,首先需要先创建一个画笔,如下:

// 1.创建一个画笔private Paint mPaint = new Paint();// 2.初始化画笔private void initPaint() {    mPaint.setColor(Color.BLACK);       //设置画笔颜色    mPaint.setStyle(Paint.Style.FILL);  //设置画笔模式为填充    mPaint.setStrokeWidth(10f);         //设置画笔宽度为10px}// 3.在构造函数中初始化public SloopView(Context context, AttributeSet attrs) {   super(context, attrs);   initPaint();}

在创建完画笔之后,就可以在Canvas中绘制各种内容了。

绘制点:
可以绘制一个点,也可以绘制一组点,如下:

canvas.drawPoint(200, 200, mPaint);     //在坐标(200,200)位置绘制一个点canvas.drawPoints(new float[]{          //绘制一组点,坐标位置由float数组指定      500,500,      500,600,      500,700},mPaint);

绘制直线:
绘制直线需要两个点,初始点和结束点,同样绘制直线也可以绘制一条或者绘制一组:

canvas.drawLine(300,300,500,600,mPaint);    // 在坐标(300,300)(500,600)之间绘制一条直线canvas.drawLines(new float[]{               // 绘制一组线 每四数字(两个点的坐标)确定一条线    100,200,200,200,    100,300,200,300},mPaint);

绘制矩形:
确定确定一个矩形最少需要四个数据,就是对角线的两个点的坐标值,这里一般采用左上角和右下角的两个点的坐标。

关于绘制矩形,Canvas提供了三种重载方法,第一种就是提供四个数值(矩形左上角和右下角两个点的坐标)来确定一个矩形进行绘制。 其余两种是先将矩形封装为Rect或RectF(实际上仍然是用两个坐标点来确定的矩形),然后传递给Canvas绘制,如下:

// 第一种canvas.drawRect(100,100,800,400,mPaint);// 第二种Rect rect = new Rect(100,100,800,400);canvas.drawRect(rect,mPaint);// 第三种RectF rectF = new RectF(100,100,800,400);canvas.drawRect(rectF,mPaint);

以上三种方法所绘制出来的结果是完全一样的。
Rect是int(整形)的,而RectF是float(单精度浮点型)的。除了精度不同,两种提供的方法也稍微存在差别

绘制圆角矩形:

绘制圆角矩形也提供了两种重载方式,如下:

// 第一种RectF rectF = new RectF(100,100,800,400);canvas.drawRoundRect(rectF,30,30,mPaint);// 第二种canvas.drawRoundRect(100,100,800,400,30,30,mPaint);

第二种方法在API21的时候才添加上
这里写图片描述
红线标注的 rx 与 ry 就是两个半径,也就是相比绘制矩形多出来的那两个参数。

绘制椭圆:

// 第一种RectF rectF = new RectF(100,100,800,400);canvas.drawOval(rectF,mPaint);// 第二种canvas.drawOval(100,100,800,400,mPaint);

绘制圆:

canvas.drawCircle(500,500,400,mPaint);  // 绘制一个圆心坐标在(500,500),半径为400 的圆。

绘制圆弧:

// 第一种public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint){}// 第二种public void drawArc(float left, float top, float right, float bottom, float startAngle,            float sweepAngle, boolean useCenter, @NonNull Paint paint) {}
startAngle  // 开始角度sweepAngle  // 扫过角度useCenter   // 是否使用中心
RectF rectF = new RectF(100,100,800,400);// 绘制背景矩形mPaint.setColor(Color.GRAY);canvas.drawRect(rectF,mPaint);// 绘制圆弧mPaint.setColor(Color.BLUE);canvas.drawArc(rectF,0,90,false,mPaint);//-------------------------------------RectF rectF2 = new RectF(100,600,800,900);// 绘制背景矩形mPaint.setColor(Color.GRAY);canvas.drawRect(rectF2,mPaint);// 绘制圆弧mPaint.setColor(Color.BLUE);canvas.drawArc(rectF2,0,90,true,mPaint);

这里写图片描述
使用了中心点之后绘制出来类似于一个扇形,而不使用中心点则是圆弧起始点和结束点之间的连线加上圆弧围成的图形。

简要介绍Paint
绘制的基本形状由Canvas确定,但绘制出来的颜色,具体效果则由Paint确定

置画笔样式的时候是这样的:

mPaint.setStyle(Paint.Style.FILL);  //设置画笔模式为填充

画笔有三种模式,如下:

STROKE                //描边FILL                  //填充FILL_AND_STROKE       //描边加填充

这里写图片描述

小示例

简要介绍画布的操作:

这里写图片描述

制作一个饼状图
这里写图片描述

用户关心的数据 : 名字 数据值 百分比

需要程序计算的数据: 百分比 对应的角度

其中颜色这一项可以用户指定也可以用程序指定(我们这里采用程序指定)。

封装数据:

public class PieData {    // 用户关心数据    private String name;        // 名字    private float value;        // 数值    private float percentage;   // 百分比    // 非用户关心数据    private int color = 0;      // 颜色    private float angle = 0;    // 角度    public PieData(@NonNull String name, @NonNull float value) {        this.name = name;        this.value = value;    }}

先按照自定义View流程梳理一遍(确定各个步骤应该做的事情):
这里写图片描述

public class PieView extends View {    // 颜色表 (注意: 此处定义颜色使用的是ARGB,带Alpha通道的)    private int[] mColors = {0xFFCCFF00, 0xFF6495ED, 0xFFE32636, 0xFF800000, 0xFF808000, 0xFFFF8C69, 0xFF808080,            0xFFE6B800, 0xFF7CFC00};    // 饼状图初始绘制角度    private float mStartAngle = 0;    // 数据    private ArrayList<PieData> mData;    // 宽高    private int mWidth, mHeight;    // 画笔    private Paint mPaint = new Paint();    public PieView(Context context) {        this(context, null);    }    public PieView(Context context, AttributeSet attrs) {        super(context, attrs);        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);        mWidth = w;        mHeight = h;    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        if (null == mData)            return;        float currentStartAngle = mStartAngle;                    // 当前起始角度        canvas.translate(mWidth / 2, mHeight / 2);                // 将画布坐标原点移动到中心位置        float r = (float) (Math.min(mWidth, mHeight) / 2 * 0.8);  // 饼状图半径        RectF rect = new RectF(-r, -r, r, r);                     // 饼状图绘制区域        for (int i = 0; i < mData.size(); i++) {            PieData pie = mData.get(i);            mPaint.setColor(pie.getColor());            canvas.drawArc(rect, currentStartAngle, pie.getAngle(), true, mPaint);            currentStartAngle += pie.getAngle();        }    }    // 设置起始角度    public void setStartAngle(int mStartAngle) {        this.mStartAngle = mStartAngle;        invalidate();   // 刷新    }    // 设置数据    public void setData(ArrayList<PieData> mData) {        this.mData = mData;        initData(mData);        invalidate();   // 刷新    }    // 初始化数据    private void initData(ArrayList<PieData> mData) {        if (null == mData || mData.size() == 0)   // 数据有问题 直接返回            return;        float sumValue = 0;        for (int i = 0; i < mData.size(); i++) {            PieData pie = mData.get(i);            sumValue += pie.getValue();       //计算数值和            int j = i % mColors.length;       //设置颜色            pie.setColor(mColors[j]);        }        float sumAngle = 0;        for (int i = 0; i < mData.size(); i++) {            PieData pie = mData.get(i);            float percentage = pie.getValue() / sumValue;   // 百分比            float angle = percentage * 360;                 // 对应的角度            pie.setPercentage(percentage);                  // 记录百分比            pie.setAngle(angle);                            // 记录角度大小            sumAngle += angle;            Log.i("angle", "" + pie.getAngle());        }    }}

PS: 在更改了数据需要重绘界面时要调用invalidate()这个函数重新绘制。

0 0