Canvas&Paint使用心得

作者: tmp_zhao | 来源:发表于2016-06-25 17:47 被阅读745次

    缘起

    自己画图在平常开发中不算很常见的需求,但偶尔有些需求还必须通过Canvas自己画出来,最近笔者就遇到了这样的事情,由于以前对这些API不是很熟悉,一路走来也是磕磕绊绊,不过总算熬过来了,最终也算是对这些API有了更深刻的认识,正好写篇文章记录下,供参考。

    实际开发中发现,当我们new一个Paint的时候,其默认的style就是FILL_AND_STROKE模式,strokeWidth默认大概1像素左右,一般如果你用到的话,最好自己设置成合适的值,单位像素。

    各种API的使用详解

    1. Canvas#drawCircle(float cx, float cy, float radius, Paint paint);
      作用:画一个圆;
      cx,cy表示圆心,radius表示半径,paint的style如果是stroke则画出来的是一个镂空的圆,否则会是填充效果的圆;
      正常画圆的时候,这个API还是很简单的,但当我们设置了paint的strokeWidth为某一具体值时,比如50px,即我们想画一个圆环效果。
      但当你通过这样的方式画一个带宽度的圆环时,半径要特别注意下,举例如下:
      假设你要在宽高都是y的矩形区域画一个宽度为strokeW的圆环,那么圆环的半径应该是:
      r1 = y /2; 外圆,紧切着最外面的矩形区域
      r2 = y/2 - strokeW; // 半径稍小的内圆
      这时,你可能以为半径为r2就ok了,可是实际测试发现,当通过drawCircle画一个带有宽度的圆时(圆环),正确的半径应该是r = r2 + strokeW/2, 比想象中的要往外再扩大点,即要加上一半的strokeW;
      可以简单理解成有宽度时,需要的半径是中心圆(即不是内圆也不是外圆)的半径(外圆半径-strokeW/2或者内圆半径+strokeW/2)。

    2. Canvas#drawOval(RectF oval, Paint paint);
      作用:画椭圆
      oval:给定的矩形区域,在这个边界内画椭圆(矩形的内切圆),如果这个矩形区域恰好是正方形,那么画出来的椭圆实际上就是圆了,介绍这个主要是为了给下面的画弧线做铺垫。

    3. Canvas#drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint);
      作用:画弧线,椭圆的某一部分;
      oval: 弧线所在的椭圆的边界矩形区域,同上面的解释;
      startAngle: 起始角度,0度是指x轴正方向(钟表上的3点钟方向),正数表示沿顺时针方向转,负数则是逆时针方向,<0或>360实际相当于startAngle%360;
      sweepAngle: 扫过的角度,正数表示顺时针扫过,负数表示逆时针扫过,如果>360 or <-360,则整个椭圆会被画出来;
      useCenter:一般为false,不包括中心点,可以设为true来画一部分扇形;

    4. Canvas#drawText(String text, float x, float y, Paint paint);
      作用:画文字,这个时候经常需要调用paint#setTextSize方法来设置文字的大小,单位是px;
      其中Paint里面的textAlign,对最终结果会有重要的影响。
      paint.setTextAlign(Paint.Align.RIGHT);
      比如text是“你好啊世界”
      假设你Text align是Left,那么 x,y是相对text的左边说的,也就是会把“你”这个文字画在x的位置;
      center也是同样的道理,x表示中间字的位置,Right是说会把“界”字画在x位置,其他文字还是会在左边依次画出来;
      这里的y是指文字的baseline,并不是我们常见的top顶部,效果上是要偏下方点,注意这个区别。

    5. Canvas#transalte(dx, dy) 平移画布
      作用:将当前的画布坐标原点移动dx,dy,比如原先是0,0,经过(100, 100)操作后,新的绘制对应的原点就是(100,100);

    6. Canvas#scale(sx, sy)、scale(sx, sy, px, py) 缩放画布
      这2个方法的区别,可以看下源码,很清楚的展现了区别:

    public void scale(float sx, float sy) {  
            native_scale(mNativeCanvasWrapper, sx, sy);
    }
    public final void scale(float sx, float sy, float px, float py) { 
            translate(px, py);    
            scale(sx, sy);    
            translate(-px, -py);
    }
    

    画布的缩放,比如scale(0.5f, 0.5f) 表示x、y方向上各缩小一半,比如画了个400*400的矩形,出来的效果就是200*200的,px,py表示对原点的平移。

    1. Canvas#rotate(float degrees, float px, float py); 旋转画布
      它的理解几乎和scale一模一样,这个方法在有些情况下是非常有用的,比如有个需求是要画个类似钟表刻度那样的界面,如下:

      钟表刻度盘
      你要做的只是画一条垂直方向的直线(线段),然后不停的旋转不同的角度即可(旋转360度),按照这个思路一下子就可以将这个复杂的问题完美解决掉。
      对这几个变换方法的理解可以参考下这篇文章,写的非常不错。
    2. 给Paint设置渐变器Shader;
      对Shader的理解可以参考这篇文章Shader图文详解
      经常我们需要用渐变色填充一个区域(比如由path决定的),实际中常用在绘制收益率曲线,然后将曲线围起来的下方区域用渐变色填充起来,示意代码如下:

     private void fillRegionWithGradientColor(Canvas canvas, Paint paint) {
            int w = getWidth();
            int h = getHeight();
    
            Path path1 = new Path();
            path1.moveTo(0, h);
            path1.lineTo(100, 200);
            path1.lineTo(150, 300);
            path1.lineTo(w/2, h/2);
            path1.lineTo(w/2+150, h/2);
    
            path1.lineTo(w, h);
           //path1.close();
    
            // 为Paint设置渐变器 在竖直方向从h/2到h渐变2个颜色值
            Shader mShader = new LinearGradient(0, h/2, 0, h, new int[] {
                    0xffff5377, 0xfffeeeee}, null,
                    Shader.TileMode.CLAMP);
            paint.setShader(mShader);
            canvas.drawPath(path1, paint);
        }
    
    1. Paint#setShadowLayer(float radius, float dx, float dy, int shadowColor);
      作用:实现在几何图形底部画阴影的效果,可以想象成阳光从上往下斜着照射;
      radius:阴影模糊层的高度,为0表示没有阴影层,值越大阴影区域越大但也更模糊,人视觉上的效果相当于在dx/dy偏移量的基础上再拼上个radius这么大的模糊层,一般你不想让它看起来很模糊的话,传一个比较小的值,比如传1就好了,注意当这个值为0时,即使有dx/dy也不会有阴影画出来;
      dx,dy:这2个值是阴影图形相对于原图形的偏移,可以想象成阳光从上往下以不同的角度照过来,比如都为正数30,相当于往右下角平移30个像素;
      shadowColor:阴影的颜色,如果这个颜色值不带透明度的话,那透明度会使用Paint的(如果它有的话),否则用阴影自己的透明度;

    总结

    这些API其实用起来也没多少难度,大家在不确定的时候最好能够动手写个小demo跑起来看看效果,一般也都能搞明白作用。

    相关文章

      网友评论

      本文标题:Canvas&Paint使用心得

      本文链接:https://www.haomeiwen.com/subject/sbdadttx.html