最近在看数字签名,在屏幕上进行书写文本信息,重写了View类里面的onDraw和onTouchEvent函数。用到了graphics下面的几个类,在网上看到几个不错的博客就在这里总结一下,算是记录一下:

就行在现实生活中写字一样,要有笔有纸,Paint类就是我们android中的画笔

下面一段参考自:http://www.cnblogs.com/-OYK/archive/2011/10/25/2223624.html  

/**   * Paint类介绍   *    * Paint即画笔,在绘图过程中起到了极其重要的作用,画笔主要保存了颜色,   * 样式等绘制信息,指定了如何绘制文本和图形,画笔对象有很多设置方法,   * 大体上可以分为两类,一类与图形绘制相关,一类与文本绘制相关。          *    * 1.图形绘制   * setARGB(int a,int r,int g,int b);   * 设置绘制的颜色,a代表透明度,r,g,b代表颜色值。   *    * setAlpha(int a);   * 设置绘制图形的透明度。   *    * setColor(int color);   * 设置绘制的颜色,使用颜色值来表示,该颜色值包括透明度和RGB颜色。   *   * setAntiAlias(boolean aa);   * 设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢。   *    * setDither(boolean dither);   * 设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰   *    * setFilterBitmap(boolean filter);   * 如果该项设置为true,则图像在动画进行中会滤掉对Bitmap图像的优化操作,加快显示   * 速度,本设置项依赖于dither和xfermode的设置   *    * setMaskFilter(MaskFilter maskfilter);   * 设置MaskFilter,可以用不同的MaskFilter实现滤镜的效果,如滤化,立体等       *    * setColorFilter(ColorFilter colorfilter);   * 设置颜色过滤器,可以在绘制颜色时实现不用颜色的变换效果   *    * setPathEffect(PathEffect effect);   * 设置绘制路径的效果,如点画线等   *    * setShader(Shader shader);   * 设置图像效果,使用Shader可以绘制出各种渐变效果   *   * setShadowLayer(float radius ,float dx,float dy,int color);   * 在图形下面设置阴影层,产生阴影效果,radius为阴影的角度,dx和dy为阴影在x轴和y轴上的距离,color为阴影的颜色   *    * setStyle(Paint.Style style);   * 设置画笔的样式,为FILL,FILL_OR_STROKE,或STROKE   *    * setStrokeCap(Paint.Cap cap);   * 当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的图形样式,如圆形样式   * Cap.ROUND,或方形样式Cap.SQUARE   *    * setSrokeJoin(Paint.Join join);   * 设置绘制时各图形的结合方式,如平滑效果等   *    * setStrokeWidth(float width);   * 当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的粗细度   *    * setXfermode(Xfermode xfermode);   * 设置图形重叠时的处理方式,如合并,取交集或并集,经常用来制作橡皮的擦除效果   *    * 2.文本绘制   * setFakeBoldText(boolean fakeBoldText);   * 模拟实现粗体文字,设置在小字体上效果会非常差   *    * setSubpixelText(boolean subpixelText);   * 设置该项为true,将有助于文本在LCD屏幕上的显示效果   *    * setTextAlign(Paint.Align align);   * 设置绘制文字的对齐方向   *   * setTextScaleX(float scaleX);  * 设置绘制文字x轴的缩放比例,可以实现文字的拉伸的效果   *    * setTextSize(float textSize);   * 设置绘制文字的字号大小   *    * setTextSkewX(float skewX);   * 设置斜体文字,skewX为倾斜弧度   *    * setTypeface(Typeface typeface);   * 设置Typeface对象,即字体风格,包括粗体,斜体以及衬线体,非衬线体等   *    * setUnderlineText(boolean underlineText);   * 设置带有下划线的文字效果   *    * setStrikeThruText(boolean strikeThruText);   * 设置带有删除线的效果   *    */  


Path类:这是个绘图的路径类,可以用他来画几何图形、画曲线、画基于路径的文本。通过 canvas.drawPath(path1, paint)方法完成绘图。

下面一段参考自:http://blog.csdn.net/liu149339750/article/details/8713498

1.addArc(RectF oval, float startAngle, float sweepAngle)

画扇形(弧线)。第二个参数为0时的位置是矩形右边1/2高度的点,90为矩形底部1/2宽的位置,如此如此....正数为顺时针旋转,负数是逆时针旋转。第三个参数是图形绘制角度,上图第三个参数为180,如果是-180,那么图形倒过来。

2.addCircle(float x, float y, float radius, Path.Direction dir)

画圆。第一、二参数是圆心坐标,第三参数是半径,第四参数是顺时针画还是逆时针画(啥玩意?)。

3.addOval(RectF oval, Path.Direction dir)

画椭圆。

4.addPath(Path src, float dx, float dy)

复制一份Path,包含被复制的src的一切,并向X与Y轴方向移动第二、三参数的距离。

5.addRect(RectF rect, Path.Direction dir)

6.addRect(float left, float top, float right, float bottom, Path.Direction dir)

画个矩形、四个参数对应与原点的相对距离的是个点。

7.addRoundRect(RectF rect, float rx, float ry, Path.Direction dir)

画圆角矩形。第二、三个参数为0时就是个矩形,为360时,就是个椭圆。第二个参数指X轴方向的角度,决定了与参考矩形的横线交点位置,0-360决定交点范围为 角点与线中点之间的某点。

8.arcTo(RectF oval, float startAngle, float sweepAngle)

等同于arcTo(RectF oval, float startAngle, float sweepAngle, boolean false)。测试发现:从之前的最后一点开始画线到画椭圆的开始点,接着画个椭圆。

9.arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)

如果最后一个参数为true,那么等同于addArc(RectF oval, float startAngle, float sweepAngle)。

10.cubicTo(float x1, float y1, float x2, float y2, float x3, float y3)

画贝塞尔曲线。前四个参数是两个控制点,最后俩个参数是终止点。起始点通过moveTo(float x, float y)或者setLastPoint(float dx, float dy)方法设置。关于贝塞尔曲线,可以去网上找找资料。某人的博客,关于此曲线

11.moveTo(float x, float y)

设置下一个图形的开始点。

12.setLastPoint(float dx, float dy)

设置图形的最后一个点位置。如果画的是个封闭图形,而这个点不在图形线上,那么这个点与最后一个图形连上线完成封闭。如图,本来画了个圆角矩形,最后setLastPoint了一下。

13.close()

关闭当前图形,如果最后一点不是开始的那点,那么从最后一点画线到开始点。简而言之,画三角型只需要画俩条线,再调此方法能三角型就完成了。

 

另外quadTo(float x1, float y1, float x2, float y2)方法:

     该方法的实现是当我们不仅仅是画一条线甚至是画弧线时会形成平滑的曲线,该曲线又称为"贝塞尔曲线"(Bezier curve),其中,x1,y1为控制点的坐标值,x2,y2为终点的坐标值;

    贝塞尔曲线的形成,就比如我们把一条橡皮筋拉直,橡皮筋的头尾部对应起点和终点,然后从拉直的橡皮筋中选择任意一点(除头尾对应的点外)扯动橡皮筋形成的弯曲形状,而那个扯动橡皮筋的点就是控制点;

 

Canvas类:  

下面是参考自:http://blog.csdn.net/lonelyroamer/article/details/8264189

Canvas的意思是画布,表现在屏幕上就是一块区域,我们可以再上面使用各种API绘制我们想要的东西。可以说,Canvas贯穿整个2D Graphics,android.graphics中的所有类,几乎都于Canvas有直接或间接的联系。所以了解Canvas是学习2D Graphics的基础。

Android官方文档对Canvas的简介很好的介绍了Canvas的使用:

[java] view plain copy print ?
  1. The Canvas class holds the "draw" calls. To draw something, you need 4 basic components: A Bitmap to hold the pixels,  
  2.  a Canvas to host the draw calls (writing into the bitmap), a drawing primitive (e.g. Rect, Path, text, Bitmap),   
  3. and a paint (to describe the colors and styles for the drawing).   
The Canvas class holds the "draw" calls. To draw something, you need 4 basic components: A Bitmap to hold the pixels, a Canvas to host the draw calls (writing into the bitmap), a drawing primitive (e.g. Rect, Path, text, Bitmap), and a paint (to describe the colors and styles for the drawing). 
一个Canvas对象有四大基本要素:

1、一个用来保存像素的Bitmap

2、一个Canvas在Bitmap上进行绘制操作

3、绘制的东西

4、绘制的画笔Paint


1、如何获得一个Canvas对象。

Canvas对象的获取方式有三种:

第一种我们通过重写View.onDraw方法,View中的Canvas对象会被当做参数传递过来,我们操作这个Canvas,效果会直接反应在View中。

第二种就是当你想自己创建一个Canvas对象。从上面的基本要素可以明白,一个Canvas对象一定是结合了一个Bitmap对象的。所以一定要为一个Canvas对象设置一个Bitmap对象。

[java] view plain copy print ?
  1. //得到一个Bitmap对象,当然也可以使用别的方式得到。但是要注意,改bitmap一定要是mutable(异变的)   
  2.         Bitmap b = Bitmap.createBitmap(100,100, Bitmap.Config.ARGB_8888);  
  3.         Canvas c = new Canvas(b);  
  4.         /*先new一个Canvas对象,在调用setBitmap方法,一样的效果 
  5.          * Canvas c = new Canvas(); 
  6.          * c.setBitmap(b); 
  7.          */  
//得到一个Bitmap对象,当然也可以使用别的方式得到。但是要注意,改bitmap一定要是mutable(异变的)        Bitmap b = Bitmap.createBitmap(100,100, Bitmap.Config.ARGB_8888);        Canvas c = new Canvas(b);        /*先new一个Canvas对象,在调用setBitmap方法,一样的效果         * Canvas c = new Canvas();         * c.setBitmap(b);         */
第三种方式,是调用SurfaceHolder.lockCanvas(),返回一个Canvas对象。


2、Canvas能绘制什么

Canvas类提供了一系列的draw...方法,从这些方法的名字就可以知道Canvas可以绘制的对象。

1、填充

[java] view plain copy print ?
  1. public void drawARGB(int a, int r, int g, int b)  
  2. public void drawColor(int color)  
  3. public void drawRGB(int r, int g, int b)  
  4. public void drawColor(int color, PorterDuff.Mode mode)  
 public void drawARGB(int a, int r, int g, int b) public void drawColor(int color) public void drawRGB(int r, int g, int b) public void drawColor(int color, PorterDuff.Mode mode)
因为Canvas内部维持了一个mutable Bitmap,所以,它可以使用这些颜色去填充整个Bitmap。并且在API中提到(restricted to the current clip)受限制于clip的范围


[java] view plain copy print ?
  1.  public void drawPaint(Paint paint)  
 public void drawPaint(Paint paint)

同理,Canvas也可以使用画笔去填充整个Bitmap,同样和填充颜色一样受限制于clip的范围,API中明确指出(This is equivalent (but faster) to drawing an
 infinitely large rectangle with the specified paint)这相当于用指定的画笔画一个更大范围的矩形,但是速度更快。

其实在Skia内部,填充调用的都是drawPaint方法的。



2、绘制几何图像

canvas.drawArc (扇形)

canvas.drawCircle(圆)

canvas.drawOval(椭圆)

canvas.drawLine(线)

canvas.drawPoint(点)

canvas.drawRect(矩形)

canvas.drawRoundRect(圆角矩形)

canvas.drawVertices(顶点)

cnavas.drawPath(路径)


3、绘制图片

canvas.drawBitmap (位图)

canvas.drawPicture (图片)


4、文本

canvas.drawText


上面列举的是Canvas所能绘制的基本内容,在实际使用中,可以使用各种过滤或者过度模式,或者其他手段,来达到绘制各种效果。


3、Canvas的变换

如果只是那些简单的draw...方法,那么canvas的功能就太单调了。Canvas还提供了一系列位置转换的方法:rorate、scale、translate、skew(扭曲)等。

[cpp] view plain copy print ?
  1. @Override  
  2.         protected void onDraw(Canvas canvas) {  
  3.             canvas.translate(100, 100);  
  4.             canvas.drawColor(Color.RED);//可以看到,整个屏幕依然填充为红色   
  5.               
  6.             canvas.drawRect(new Rect(-100, -100, 0, 0), new Paint());//缩放了   
  7.             canvas.scale(0.5f, 0.5f);  
  8.             canvas.drawRect(new Rect(0, 0, 100, 100), new Paint());  
  9.               
  10.             canvas.translate(200, 0);  
  11.             canvas.rotate(30);  
  12.             canvas.drawRect(new Rect(0, 0, 100, 100), new Paint());//旋转了   
  13.               
  14.             canvas.translate(200, 0);  
  15.             canvas.skew(.5f, .5f);//扭曲了   
  16.             canvas.drawRect(new Rect(0, 0, 100, 100), new Paint());  
  17.             // canvas.setMatrix(matrix);//Matrix的使用在后面在是。   
  18.         }  
@Override        protected void onDraw(Canvas canvas) {            canvas.translate(100, 100);            canvas.drawColor(Color.RED);//可以看到,整个屏幕依然填充为红色                        canvas.drawRect(new Rect(-100, -100, 0, 0), new Paint());//缩放了            canvas.scale(0.5f, 0.5f);            canvas.drawRect(new Rect(0, 0, 100, 100), new Paint());                        canvas.translate(200, 0);            canvas.rotate(30);            canvas.drawRect(new Rect(0, 0, 100, 100), new Paint());//旋转了                        canvas.translate(200, 0);            canvas.skew(.5f, .5f);//扭曲了            canvas.drawRect(new Rect(0, 0, 100, 100), new Paint());            // canvas.setMatrix(matrix);//Matrix的使用在后面在是。        }


Canvas虽然内部保持了一个Bitmap,但是它本身并不代表那个Bitmap,而更像是一个图层。我们对这个图层的平移旋转和缩放等等操作,并不影响内部的Bitmap,仅仅是改变了该图层相对于内部Bitmap 的坐标位置、比例和方向而已。


4、Canvas的保存和回滚

为了方便一些转换操作,Canvas还提供了保存和回滚属性的方法(save和restore),比如你可以先保存目前画纸的位置(save),然后旋转90度,向下移动100像素后画一些图形,画完后调用restore方法返回到刚才保存的位置。

Canvas提供的该功能的API如下:

[java] view plain copy print ?
  1. /** 
  2.      * 保存当前的matrix和clip到私有的栈中(Skia内部实现)。任何matrix变换和clip操作都会在调用restore的时候还原。 
  3.      * @return 返回值可以传入到restoreToCount()方法,以返回到某个save状态之前。 
  4.      */  
  5.     public native int save();  
  6.       
  7.   
  8.   
  9.     /** 
  10.      * 传入一个标志,来表示当restore 的时候,哪些参数需要还原。该参数定义在Canvas中,参照下面。 
  11.      * save()方法默认的是还原matrix和clip,但是可以使用这个方法指定哪些需要还原。并且只有指定matrix和clip才有效,其余的几个参数是 
  12.      * 用于saveLayer()和saveLayerAlpha()方法 的。 
  13.      */  
  14.     public native int save(int saveFlags);  
  15.   
  16.   
  17.     /** 
  18.      * 回到上一个save调用之前的状态,如果restore调用的次数大于save方法,会出错。 
  19.      */  
  20.     public native void restore();  
  21.   
  22.      /** 
  23.      * 返回栈中保存的状态,值等译 save()调用次数-restore()调用次数 
  24.      */  
  25.     public native int getSaveCount();  
  26.   
  27.   
  28.       
  29.   
  30.     /** 
  31.      * 回到任何一个save()方法调用之前的状态 
  32.      */  
  33.     public native void restoreToCount(int saveCount);  
  34.   
  35.   
  36.   
  37. /**saveFlags的参数*/  
  38.  public static final int MATRIX_SAVE_FLAG = 0x01;//需要还原Matrix   
  39.     public static final int CLIP_SAVE_FLAG = 0x02;//需要还原Clip   
  40. /**下面三个参数在saveLayer的时候使用,具体作用,没有搞明白*/  
  41.    public static final int HAS_ALPHA_LAYER_SAVE_FLAG = 0x04;  
  42.   public static final int FULL_COLOR_LAYER_SAVE_FLAG = 0x08;  
  43.   public static final int CLIP_TO_LAYER_SAVE_FLAG = 0x10;  
  44.     public static final int ALL_SAVE_FLAG = 0x1F//还原所有   
  45.   
  46. /*关于saveLayer的具体flags还不大明白它的含义,具体怎么使用在下面例子中*/  
  47.  public int saveLayer(RectF bounds, Paint paint, int saveFlags)  
  48. public int saveLayer(float left, float top, float right, float bottom,  
  49.                          Paint paint, int saveFlags)   
  50.  public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags)  
  51. public int saveLayerAlpha(float left, float top, float right, float bottom,  
  52.                               int alpha, int saveFlags)  
/**     * 保存当前的matrix和clip到私有的栈中(Skia内部实现)。任何matrix变换和clip操作都会在调用restore的时候还原。     * @return 返回值可以传入到restoreToCount()方法,以返回到某个save状态之前。     */    public native int save();        /**     * 传入一个标志,来表示当restore 的时候,哪些参数需要还原。该参数定义在Canvas中,参照下面。     * save()方法默认的是还原matrix和clip,但是可以使用这个方法指定哪些需要还原。并且只有指定matrix和clip才有效,其余的几个参数是     * 用于saveLayer()和saveLayerAlpha()方法 的。     */    public native int save(int saveFlags);    /**     * 回到上一个save调用之前的状态,如果restore调用的次数大于save方法,会出错。     */    public native void restore();     /**     * 返回栈中保存的状态,值等译 save()调用次数-restore()调用次数     */    public native int getSaveCount();        /**     * 回到任何一个save()方法调用之前的状态     */    public native void restoreToCount(int saveCount);/**saveFlags的参数*/ public static final int MATRIX_SAVE_FLAG = 0x01;//需要还原Matrix    public static final int CLIP_SAVE_FLAG = 0x02;//需要还原Clip/**下面三个参数在saveLayer的时候使用,具体作用,没有搞明白*/   public static final int HAS_ALPHA_LAYER_SAVE_FLAG = 0x04;  public static final int FULL_COLOR_LAYER_SAVE_FLAG = 0x08;  public static final int CLIP_TO_LAYER_SAVE_FLAG = 0x10;    public static final int ALL_SAVE_FLAG = 0x1F; //还原所有/*关于saveLayer的具体flags还不大明白它的含义,具体怎么使用在下面例子中*/ public int saveLayer(RectF bounds, Paint paint, int saveFlags)public int saveLayer(float left, float top, float right, float bottom,                         Paint paint, int saveFlags)  public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags)public int saveLayerAlpha(float left, float top, float right, float bottom,                              int alpha, int saveFlags)



saveLayer

Canvas 在一般的情况下可以看作是一张画布,所有的绘图操作如drawBitmap, drawCircle都发生在这张画布上,这张画板还定义了一些属性比如Matrix,颜色等等。但是如果需要实现一些相对复杂的绘图操作,比如多层动画,地图(地图可以有多个地图层叠加而成,比如:政区层,道路层,兴趣点层)。Canvas提供了图层(Layer)支持,缺省情况可以看作是只有一个图层Layer。如果需要按层次来绘图,Android的Canvas可以使用SaveLayerXXX, Restore 来创建一些中间层,对于这些Layer是按照“栈结构“来管理的:       


 创建一个新的Layer到“栈”中,可以使用saveLayer, savaLayerAlpha, 从“栈”中推出一个Layer,可以使用restore,restoreToCount。但Layer入栈时,后续的DrawXXX操作都发生在这个Layer上,而Layer退栈时,就会把本层绘制的图像“绘制”到上层或是Canvas上,在复制Layer到Canvas上时,可以指定Layer的透明度(Layer),这是在创建Layer时指定的:public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags)本例Layers 介绍了图层的基本用法:Canvas可以看做是由两个图层(Layer)构成的,为了更好的说明问题,我们将代码稍微修改一下,缺省图层绘制一个红色的圆,在新的图层画一个蓝色的圆,新图层的透明度为0×88。      

[java] view plain copy print ?
  1. public class Layers extends Activity {  
  2.   
  3.     @Override  
  4.     protected void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.         setContentView(new SampleView(this));  
  7.     }  
  8.   
  9.     private static class SampleView extends View {  
  10.         private static final int LAYER_FLAGS = Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG  
  11.                 | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG  
  12.                 | Canvas.CLIP_TO_LAYER_SAVE_FLAG;  
  13.   
  14.         private Paint mPaint;  
  15.   
  16.         public SampleView(Context context) {  
  17.             super(context);  
  18.             setFocusable(true);  
  19.   
  20.             mPaint = new Paint();  
  21.             mPaint.setAntiAlias(true);  
  22.         }  
  23.   
  24.         @Override  
  25.         protected void onDraw(Canvas canvas) {  
  26.             canvas.drawColor(Color.WHITE);    
  27.             canvas.translate(1010);    
  28.             mPaint.setColor(Color.RED);    
  29.             canvas.drawCircle(757575, mPaint);    
  30.             canvas.saveLayerAlpha(002002000x88, LAYER_FLAGS);    
  31.             mPaint.setColor(Color.BLUE);    
  32.             canvas.drawCircle(12512575, mPaint);    
  33.             canvas.restore();   
  34.          }  
  35.     }  
  36. }  
public class Layers extends Activity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(new SampleView(this));    }    private static class SampleView extends View {        private static final int LAYER_FLAGS = Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG                | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG                | Canvas.CLIP_TO_LAYER_SAVE_FLAG;        private Paint mPaint;        public SampleView(Context context) {            super(context);            setFocusable(true);            mPaint = new Paint();            mPaint.setAntiAlias(true);        }        @Override        protected void onDraw(Canvas canvas) {            canvas.drawColor(Color.WHITE);              canvas.translate(10, 10);              mPaint.setColor(Color.RED);              canvas.drawCircle(75, 75, 75, mPaint);              canvas.saveLayerAlpha(0, 0, 200, 200, 0x88, LAYER_FLAGS);              mPaint.setColor(Color.BLUE);              canvas.drawCircle(125, 125, 75, mPaint);              canvas.restore();          }    }}



 

更多相关文章

  1. Android消息机制及HandlerThread、Handler内存泄漏问题
  2. Android事件传递机制(更加深入的了解事件的触发过程)
  3. android HTTP 通信, XML 解析, 通过 Hander 实现异步消息处理 (1)
  4. Android中Matrix的pre post set方法理解(来源:Linux社区 作者:zjmd
  5. XML解析(一),SAX解析XML
  6. Android的Aidl安装方法
  7. AIDL --- Android中的远程接口(2)
  8. android App全局SD卡路径统一管理
  9. Android6.0权限系统

随机推荐

  1. 实现一个Android输入法
  2. Android构建面试知识
  3. Android(安卓)中自定义控件和属性(attr.x
  4. Android(安卓)UI目录
  5. 博文视点大讲堂37期 ——It's Android Ti
  6. Android上的单元测试shell
  7. 【译】Google官方推出的Android架构组件
  8. Android双机(网络和USB)调试及其完美ROOT
  9. 如何成为一名Android架构师,乃至高级架构
  10. Android(安卓)-计算器的实现