完全自定义控件-Canvas之绘制基本形状
nabb4738
8年前
<h3>一.简介</h3> <p>Canvas 美[ˈkænvəs] 画布</p> <p>Canvas绘图有三个基本要素:Canvas、绘图坐标系以及Paint。</p> <ul> <li>Canvas是画布,我们通过Canvas的各种drawXXX方法将图形绘制到Canvas上面,在drawXXX方法中我们需要传入要绘制的图形的坐标形状,还要传入一个画笔Paint。</li> <li>drawXXX方法以及传入其中的坐标决定了要绘制的图形的形状,比如drawCircle方法,用来绘制圆形,需要我们传入圆心的x和y坐标,以及圆的半径。</li> <li>drawXXX方法中传入的画笔Paint决定了绘制的图形的一些外观,比如是绘制的图形的颜色,再比如是绘制圆面还是圆的轮廓线等。</li> <li>Canvas的drawXXX方法中传入的各种坐标指的都是绘图坐标系中的坐标。在初始状况下,绘图坐标系的坐标原点在View的左上角。<br> 但绘图坐标系可以改变,例如translate方法,可以平移坐标系。且坐标系的位移是基于当前位置移动,而不是每次基于屏幕左上角的(0,0)点移动。</li> </ul> <h3>二.Canvas的常用操作速查表</h3> <table> <thead> <tr> <th>操作类型</th> <th>相关API</th> <th>备注</th> </tr> </thead> <tbody> <tr> <td>绘制颜色</td> <td>drawColor, drawRGB, drawARGB</td> <td>使用单一颜色填充整个画布</td> </tr> <tr> <td>绘制基本形状</td> <td>drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc</td> <td>依次为 点、线、矩形、圆角矩形、椭圆、圆、圆弧</td> </tr> <tr> <td>绘制图片</td> <td>drawBitmap, drawPicture</td> <td>绘制位图和图片</td> </tr> <tr> <td>绘制文本</td> <td>drawText, drawPosText, drawTextOnPath</td> <td>依次为 绘制文字、绘制文字时指定每个文字位置、根据路径绘制文字</td> </tr> <tr> <td>绘制路径</td> <td>drawPath</td> <td>绘制路径,绘制贝塞尔曲线时也需要用到该函数</td> </tr> <tr> <td>顶点操作</td> <td>drawVertices, drawBitmapMesh</td> <td>通过对顶点操作可以使图像形变,drawVertices直接对画布作用、 drawBitmapMesh只对绘制的Bitmap作用</td> </tr> <tr> <td>画布剪裁</td> <td>clipPath, clipRect</td> <td>设置画布的显示区域</td> </tr> <tr> <td>画布快照</td> <td>save, restore, saveLayerXxx, restoreToCount, getSaveCount</td> <td>依次为 保存当前状态、 回滚到上一次保存的状态、 保存图层状态、 回滚到指定状态、 获取保存次数</td> </tr> <tr> <td>画布变换</td> <td>translate, scale, rotate, skew</td> <td>依次为 位移、缩放、 旋转、错切</td> </tr> <tr> <td>Matrix(矩阵)</td> <td>getMatrix, setMatrix, concat</td> <td>实际画布的位移,缩放等操作的都是图像矩阵Matrix,只不过Matrix比较难以理解和使用,故封装了一些常用的方法。</td> </tr> </tbody> </table> <h3>三.实战</h3> <p>绘制颜色 drawARGB:</p> <p>绘制颜色是填充整个画布,常用于绘制底色。</p> <ol> <li>新建CanvasView类继承View</li> <li>重写onDraw</li> </ol> <pre> <code class="language-java">public class CanvasView extends View { //在代码中定义和使用时用到的 public CanvasView(Context context) { super(context); } //在xml中定义我们的自定义属性时用到 public CanvasView(Context context, AttributeSet attrs) { super(context, attrs); } //在View中画出我们需要的内容 @Override protected void onDraw(Canvas canvas) { canvas.drawARGB(255, 139, 197, 186); } }</code></pre> <p><img src="https://simg.open-open.com/show/5ec661f8a64dadf447202bf434bf2f3f.png"></p> <p>绘制画布</p> <p>绘制点 drawPoint:</p> <ol> <li>在构造函数中初始化画笔</li> <li>重写onDraw</li> </ol> <pre> <code class="language-java">public class CanvasView extends View { private Paint mPaint; //在代码中定义和使用时用到的 public CanvasView(Context context) { super(context); init(); } //在xml中定义我们的自定义属性时用到 public CanvasView(Context context, AttributeSet attrs) { super(context, attrs); init(); } //在构造函数中初始化画笔 private void init() { mPaint = new Paint(); mPaint.setColor(Color.BLACK); //设置画笔颜色 mPaint.setStyle(Paint.Style.FILL); //设置画笔模式为填充 mPaint.setStrokeWidth(10f); //设置画笔宽度为10px } //在View中画出我们需要的内容 @Override protected void onDraw(Canvas canvas) { canvas.drawPoint(100, 100, mPaint); //在坐标(100,100)位置绘制一个点 canvas.drawPoints(new float[]{ //绘制一组点,坐标位置由float数组指定 200, 200, 300, 400, 400, 500 }, mPaint); } }</code></pre> <p><img src="https://simg.open-open.com/show/534ec3a08ea01e077ab42962b5eb6ee1.png"></p> <p>绘制点</p> <p>绘制直线 drawLine:</p> <pre> <code class="language-java">protected void onDraw(Canvas canvas) { mPaint.setColor(Color.GREEN);// 设置绿色 canvas.drawLine(60, 40, 100, 40, mPaint);// 画线 canvas.drawLine(110, 40, 190, 80, mPaint);// 斜线 canvas.drawLines(new float[]{ // 绘制一组线 每四数字(两个点的坐标)确定一条线 100,200,200,200, 100,300,200,300 },mPaint); }</code></pre> <p><img src="https://simg.open-open.com/show/630dd0845f8fccb5572170245f4abd4a.png"></p> <p>绘制直线</p> <p>绘制矩形 drawRect:</p> <p>确定确定一个矩形最少需要四个数据,就是对角线的两个点的坐标值,这里一般采用左上角和右下角的两个点的坐标。</p> <pre> <code class="language-java">protected void onDraw(Canvas canvas) { //取得画布的宽高 int canvasWidth = canvas.getWidth(); int canvasHeight = canvas.getHeight(); //设置画笔的填充色是蓝色 mPaint.setColor(Color.BLUE); int left1 = 10; int top1 = 10; int right1 = canvasWidth / 3; int bottom1 = canvasHeight /3; canvas.drawRect(left1, top1, right1, bottom1, mPaint); //修改画笔颜色 mPaint.setColor(Color.RED); int left2 = canvasWidth / 3 * 2; int top2 = 10; int right2 = canvasWidth - 10; int bottom2 = canvasHeight / 3; canvas.drawRect(left2, top2, right2, bottom2, mPaint); }</code></pre> <ul> <li>简单画了下法国国旗</li> </ul> <p><img src="https://simg.open-open.com/show/8d1925f0327d7a35d59cb82fb6c1aff5.png"></p> <p>绘制矩形</p> <p>绘制圆角矩形 drawRoundRect:</p> <pre> <code class="language-java">protected void onDraw(Canvas canvas) { mPaint.setColor(0xff8bc5ba);//A:ff,R:8b,G:c5,B:ba RectF rectF = new RectF(10,10,300,150); //这里的圆弧是椭圆的圆弧,所以要设置椭圆的两个半径 canvas.drawRoundRect(rectF,10,10,mPaint); }</code></pre> <p><img src="https://simg.open-open.com/show/6ef7b94eb5ca3285be34a646ca38e117.png"></p> <p>rx,ry</p> <p><img src="https://simg.open-open.com/show/e447ff43b3617831fe459332ab76a2bc.png"></p> <p>绘制圆角矩形</p> <p>绘制圆、圆环和椭圆 drawCircle、drawOval:</p> <pre> <code class="language-java">protected void onDraw(Canvas canvas) { mPaint.setColor(0xff8bc5ba); mPaint.setAntiAlias(true); //设置画笔为抗锯齿模式,不然画出来太丑了 mPaint.setStyle(Paint.Style.FILL);//默认绘图为填充模式 int canvasWidth = canvas.getWidth(); int canvasHeight = canvas.getHeight(); int halfCanvasWidth = canvasWidth / 2; int R = canvasHeight / 9; // 绘制一个矩形的内切椭圆 RectF rectF = new RectF(100, 10, 370, 150); canvas.drawOval(rectF, mPaint); // 绘制一个圆心坐标在(halfCanvasWidth,250),半径为R 的圆 canvas.drawCircle(halfCanvasWidth, 250, R, mPaint); //通过绘制两个圆形成圆环 //1. 首先绘制大圆 canvas.drawCircle(halfCanvasWidth, 450, R, mPaint); //2. 然后绘制小圆,让小圆覆盖大圆,形成圆环效果 int r = (int) (R * 0.75); mPaint.setColor(0xffffffff);//将画笔设置为白色,画小圆 canvas.drawCircle(halfCanvasWidth, 450, r, mPaint); //通过画笔的描边绘图模式绘制圆环 mPaint.setColor(0xff8bc5ba);//设置颜色 mPaint.setStyle(Paint.Style.STROKE);//绘图为描边模式 float strokeWidth = (float) (R * 0.25); //设置线条宽度 mPaint.setStrokeWidth(strokeWidth); canvas.drawCircle(halfCanvasWidth, 650, R, mPaint); }</code></pre> <p><img src="https://simg.open-open.com/show/09a6804458b06420efa5d3d230a68f5f.png"></p> <p>绘制圆、圆环、椭圆</p> <ul> <li>简要介绍Paint的模式 <ul> <li>STROKE 描边,把边给填充颜色</li> <li>FILL 填充,填充边中的内容</li> <li>FILL_AND_STROKE 描边加填充,就是把上面两个合起来</li> </ul> </li> </ul> <p>绘制圆弧 drawArc:</p> <p>Canvas中提供了drawArc方法用于绘制弧,这里的弧指两种:弧面和弧线,弧面即用弧围成的填充面,弧线即为弧面的轮廓线。</p> <pre> <code class="language-java">public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint){}</code></pre> <ul> <li>oval是RecF类型的对象,其定义了椭圆的形状。</li> <li>startAngle指的是绘制的起始角度,如果传入的startAngle小于0或者大于等于360,那么用startAngle对360进行取模后作为起始绘制角度。</li> <li>sweepAngle指的是从startAngle开始沿着钟表的顺时针方向旋转扫过的角度。如果sweepAngle大于等于360,那么会绘制完整的椭圆弧。如果sweepAngle小于0,那么会用sweepAngle对360进行取模后作为扫过的角度。</li> <li> <p>useCenter是个boolean值,如果为true,表示在绘制完弧之后,用椭圆的中心点连接弧上的起点和终点以闭合弧;如果值为false,表示在绘制完弧之后,弧的起点和终点直接连接,不经过椭圆的中心点。</p> <pre> <code class="language-java">protected void onDraw(Canvas canvas) { int canvasWidth = canvas.getWidth(); int canvasHeight = canvas.getHeight(); //把画布分成五份 float ovalHeight = canvasHeight / 5; float left = 10 ; float top = 0; float right = canvasWidth - left; float bottom= ovalHeight; RectF rectF = new RectF(left, top, right, bottom); mPaint.setAntiAlias(true); //抗锯齿 mPaint.setStrokeWidth(5);//设置线宽 mPaint.setColor(0xff8bc5ba);//设置颜色 mPaint.setStyle(Paint.Style.FILL);//默认设置画笔为填充模式 //绘制用drawArc绘制完整的椭圆 canvas.drawArc(rectF, 0, 360, true, mPaint); //绘制椭圆的四分之一,起点是0度,到90度 canvas.translate(0, ovalHeight ); //绘图坐标系平移操作,x轴移动0,y轴移动五分之一个画布长度 canvas.drawArc(rectF, 0, 90, true, mPaint); //绘制椭圆的四分之一,将useCenter设置为false canvas.translate(0, ovalHeight ); canvas.drawArc(rectF, 0, 90, false, mPaint); //绘制椭圆的四分之一,只绘制轮廓线 mPaint.setStyle(Paint.Style.STROKE);//设置画笔为描边模式 canvas.translate(0, ovalHeight ); canvas.drawArc(rectF, 0, 90, true, mPaint); //绘制带有轮廓线的椭圆的四分之一 //1. 先绘制椭圆的填充部分 mPaint.setStyle(Paint.Style.FILL);//设置画笔为填充模式 canvas.translate(0, ovalHeight ); canvas.drawArc(rectF, 0, 90, true, mPaint); //2. 再绘制椭圆的轮廓线部分 mPaint.setStyle(Paint.Style.STROKE);//设置画笔为线条模式 mPaint.setColor(0xff0000ff);//设置轮廓线条为蓝色 canvas.drawArc(rectF, 0, 90, true, mPaint); }</code></pre> </li> </ul> <p><img src="https://simg.open-open.com/show/8a0b48033e3e95a9c85791910919a143.png"></p> <p>绘制圆弧</p> <p>自定义饼图:</p> <p>学了那么大堆基础终于可以画个能用的图了</p> <p><img src="https://simg.open-open.com/show/19217b2a6df768ddb8afee865b676225.png"></p> <p>自定义饼图</p> <pre> <code class="language-java">protected void onDraw(Canvas canvas) { RectF rectF = new RectF(100, 100, 400, 400); mPaint.setAntiAlias(true); //抗锯齿 mPaint.setStrokeWidth(5);//设置线宽 mPaint.setColor(0xFFCCFF00);//设置颜色 mPaint.setStyle(Paint.Style.FILL);//默认设置画笔为填充模式 canvas.drawArc(rectF, 0, 110, true, mPaint); mPaint.setColor(0xff8bc5ba);//设置颜色 canvas.drawArc(rectF, 110, 50, true, mPaint); mPaint.setColor( 0xFF800000);//设置颜色 canvas.drawArc(rectF, 160, 80, true, mPaint); mPaint.setColor(0xFFFF8C69);//设置颜色 canvas.drawArc(rectF, 240, 120, true, mPaint); }</code></pre> <p>这里是 <a href="/misc/goto?guid=4959677322699270043" rel="nofollow,noindex">项目地址</a></p> <p>参考</p> <p><a href="/misc/goto?guid=4958971965986394434" rel="nofollow,noindex">http://blog.csdn.net/iispring/article/details/49770651</a></p> <p><a href="/misc/goto?guid=4959677322830800930" rel="nofollow,noindex">https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/%5B02%5DCanvas_BasicGraphics.md</a></p> <p> </p> <p>来自:http://www.jianshu.com/p/282958cdbf25</p> <p> </p>