完全自定义控件-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>