Android 绘图基础Canvas

转载子:Android 2D Graphics学习

一个Canvas对象有四大基本要素:
1、一个用来保存像素的Bitmap
2、一个Canvas在Bitmap上进行绘制操作
3、绘制的东西
4、绘制的画笔Paint

1、如何获得一个Canvas对象

Canvas对象的获取方式有三种:
1. 我们通过重写View.onDraw方法,View中的Canvas对象会被当做参数传递过来,我们操作这个Canvas,效果会直接反应在View中

performTraversals方法中ViewRootImpl就会去创建Surface,而此后的渲染则可以通过Surface的lockCanvas方法获取Surface的Canvas来进行,然后遍历ViewHierachy把需要绘制的View通过Canvas(View.onDraw(Canvas canvas))绘制到Surface上,绘制完成后解锁(Surface.unlockCanvasAndPost)让SurfaceFlinger将Surface绘制到屏幕上。我们onDraw(Canvas canvas)方法中传入的Canvas对象大致就是这么来的…..Surface对应了一块屏幕缓冲区,每个window对应一个Surface,任何View都是画在Surface上的,传统的view共享一块屏幕缓冲区,所有的绘制必须在UI线程中进行.但是viewgroup在依次绘制子view的时候,都会先对canvas进行save操作,绘制完之后restore,所以其实虽然绘制都共用同一个canvas,但是子view之间的绘制是互不影响的

这种方式,canvas默认有一个系统的bitmap对象
2. 就是当你想自己创建一个Canvas对象。从上面的基本要素可以明白,一个Canvas对象一定是结合了一个Bitmap对象的,所以一定要为一个Canvas对象设置一个Bitmap对象

        //得到一个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); 

         */  

3.是调用SurfaceHolder.lockCanvas(),返回一个Canvas对象,此时感觉就跟onDraw(Canvas canvas)中的一样了……

2、Canvas能绘制什么

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

1、填充


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的范围

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方法的。

此时受限于clip范围的,但是不受限于matrix变换的,因为这几个是填充…….另一方面clip受matrix影响,除了clipRegion

clipRect和clipPath要使用当前的matrix进行变换不同。clipRegion不会进行转换。也就是说canvas的matrix对clipRegion没有影响

2、绘制几何图像

canvas.drawArc (扇形)

canvas.drawCircle(圆)

canvas.drawOval(椭圆)

canvas.drawLine(线)

canvas.drawPoint(点)

canvas.drawRect(矩形)

canvas.drawRoundRect(圆角矩形)

canvas.drawVertices(顶点)

cnavas.drawPath(路径)

同时受限于clip和matrix

3、绘制图片

canvas.drawBitmap (位图)

canvas.drawPicture (图片)

同时受限于clip和matrix

4、文本

canvas.drawText

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

过渡模式:

Xfermode,AvoidXfermode,PixelXorXfermode,PorterDuffXfermode

PorterDuff

过滤

1、rgb过滤 ColorFilter ,ColorMatrixFilter,PorterDuffColorFilter,LightingColorFilter,PorterDuffColorFilter

2、alpha过滤 MaskFilter,BlurMaskFilter,EmbossMaskFilter

3、DrawFilter,PaintFlagsDrawFilter

变换

Matrix,Camera,ColorMatrix

颜色

Color

渐变

Shader

BitmapShader,ComposeShader,LinearGradient,RadialGradient,SweepGradient

3、Canvas的变换

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


        @Override  

        protected void onDraw(Canvas canvas) {  

            canvas.translate(100, 100);  //把画布的中心坐标切换到(100, 100)

            canvas.drawColor(Color.RED);//可以看到,整个屏幕依然填充为红色,所以也是说不受matrix影响  



            canvas.drawRect(new Rect(-100, -100, 0, 0), new Paint());//注意此时是以(100, 100)点来进行平移的  

            canvas.scale(0.5f, 0.5f);  

            canvas.drawRect(new Rect(0, 0, 100, 100), new Paint());  //受matrix影响,实际上只画了个50大小的矩形,同时注意中心点在(100, 100)



            canvas.translate(200, 0);  //此时也受了scale的影响,在(100, 100)基础上实际右平移了100,所以此时中心坐标(200,100)

            canvas.rotate(30);  

            canvas.drawRect(new Rect(0, 0, 100, 100), new Paint()); //按照中心坐标(200,100)中心点旋转,但是矩阵的大小还是50,



            canvas.translate(200, 0);  //此时既要收到scale0.5影响也受到了rotate30的影响,所以可以计算出新的中心坐标为多少

            canvas.skew(.5f, .5f);//扭曲了  

            canvas.drawRect(new Rect(0, 0, 100, 100), new Paint());  //既有缩放,旋转也有错切

            // canvas.setMatrix(matrix);//Matrix的使用在后面在是。  

        }

注意canvas的matrix其实最后都是操作在像素点上的

4、Canvas的保存和回滚

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

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


    /** 

     * 保存当前的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);  

    /**

     * 合并目前的矩阵

     */

    public void concat(@Nullable Matrix matrix) {

        if (matrix != null) native_concat(mNativeCanvasWrapper, matrix.native_instance);

    }



    /**

     * 完全替代目前的矩阵,有时候使用该方法无效,需要使用concat方法,硬件加速相关

     */

    public void setMatrix(@Nullable Matrix matrix) {

        native_setMatrix(mNativeCanvasWrapper,

                         matrix == null ? 0 : matrix.native_instance);

    }



/**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)  

canvas的裁剪

1、什么是裁剪

裁剪Clip,即裁剪Canvas图层,我们绘制的东西,只能在裁剪区域的范围能才能显示出来。 跟Matrix的区别,matrix是像素点进行矩阵操作,clip限定像素点显示范围


        @Override  

        protected void onDraw(Canvas canvas) {  

              Paint paint=new Paint();   

              canvas.save();   

              canvas.clipRect(new Rect(100,100,300,300));  

              canvas.drawColor(Color.BLUE);//裁剪区域的rect变为蓝色   

              canvas.drawRect(new Rect(0,0,100,100), paint);//在裁剪的区域之外,不能显示   

              canvas.drawCircle(150,150, 50, paint);//在裁剪区域之内,能显示  

              canvas.restore();  

        }

2、裁剪的保存和回滚

在之前已经提到了,canvas.save()和canvas.restore()不仅对matrix有效,同样对clip有类似的效果。

3、裁剪的方式

Canvas提供了三种裁剪的方式:

1、最基本的clipRect,裁剪一个矩形

2、clipPath,裁剪Path包括的范围,Path所包括的范围不是空的才有效。

3、clipRegion

与clipRect和clipPath要使用当前的matrix进行变换不同。clipRegion不会进行转换。也就是说canvas的matrix对clipRegion没有影响。


 Paint paint=new Paint();  

 canvas.scale(0.5f, 0.5f);  

 canvas.save();  

 canvas.clipRect(new Rect(100,100,200,200));//裁剪区域实际大小为50*50  

 canvas.drawColor(Color.RED);  

 canvas.restore();  



 canvas.drawRect(new Rect(0,0,100,100), paint);//矩形实际大小为50*50  



 canvas.clipRegion(new Region(new Rect(300,300,400,400)));//裁剪区域实际大小为100*100  

 canvas.drawColor(Color.BLACK); 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android自定义ViewCanvas是一个绘图容器,可以在其上进行2D绘图操作。通过Canvas,我们可以绘制图形、文字、位图等。 要在自定义View使用Canvas,需要重写ViewonDraw()方法,并在该方法获取Canvas实例,然后进行绘制操作。 下面是一个简单的示例代码,展示如何在自定义View使用Canvas绘制一个矩形: ```java public class MyCustomView extends View { public MyCustomView(Context context) { super(context); } public MyCustomView(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(); paint.setColor(Color.RED); paint.setStyle(Paint.Style.FILL); canvas.drawRect(100, 100, 300, 300, paint); } } ``` 在这个示例,我们创建了一个名为MyCustomView的自定义View,并重写了它的onDraw()方法。在该方法,我们首先创建了一个Paint对象,设置了画笔的颜色为红色,并指定绘制的样式为填充。然后,使用Canvas的drawRect()方法绘制一个矩形,坐标为(100, 100)到(300, 300)。 当我们在布局文件使用这个自定义View时,它会自动调用onDraw()方法进行绘制,从而在屏幕上显示出红色矩形。 需要注意的是,Canvas提供了许多其他绘制方法,如drawCircle()、drawText()等,可以根据需求选择合适的方法进行绘制操作。此外,还可以通过设置Paint对象的属性来实现不同的绘制效果,如线条宽度、字体大小等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值