Android Canvas

本文介绍了Android Canvas的使用,包括填充颜色、绘制形状、绘制图片和文字。重点讨论了Canvas的save和restore方法,save用于保存当前画布状态,restore则恢复到之前保存的状态,确保在复杂绘图操作中能正确回溯。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android Canvas


1、前言

前面我们介绍过了Android中的图片相关的两个类,一个是Drawable,一个是Bitmap,这两个类在Android的绘图技巧当中是十分的重要的。这里不再多做解释,如果还存在一些疑问或者困惑的可以去看看我的前两篇博客,我们现在明白了给哪里绘制,下来我们就需要接触到我们的绘图核心类了,–Canvas了,相信大家在工作和学习当中绝对比较熟悉这个类。好了,我们开始我们今天的正题,我们和以前一样,我们先列出我们今天要探索的东西,如果您都掌握了,那就直接跳,免得浪费大家的时间,程序员的时间,是很珍贵的。

这里写图片描述


2、Cnavas

我们看到上述的导航图了,今天我们的要聊的话题就是Canvas,并且博主打算分成两个部分去介绍Canvas,第一部分就是关于Canvas的基本使用的方法就是画点东西出来,第二个方面就是主要聊一聊我们Canvas的绘图技巧,如何我们进行高效的绘图呢,

不过在开始之前,我们需要先弄明白一个概念,那就是我们的Canvas是什么,我们知道Bitmap主要负责保存我们的像素数据,我们想给我们的Bitmap去操作像素数据(绘制),Google官方给我们提供了一个叫做Canvas的类,就是画布,根据面向对象的思想,画什么东西是画布的动作,所以在该画布里面封装了大量的API来供我们进行使用,大体的可以分为5大类,具体是什么,在我的上图当中已经有明确的答案了。那我们就来看看吧

3、绘制图像

我们首先得知道如何得到一个Canvas,我们刚刚说过了,我们的Canvas应该与一个Bitmap所绑定的在一起比如下面的这一条示例,我们的Canvas应该和我们的Bitmap进行绑定。绑定以后我们的Bitmap就会接受你在画布上面所绘制的一切。

Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
//根据我们上述创建出来的Bitmap去创建一个画布,
Canvas canvas = new Canvas(bitmap);
//这一行代码一执行,我们所画的东西就通过画布去绘制到我们刚刚创建出来的Bitmap之上了
canvas.drawXXXX();
  • 填充颜色
//去在画布上面绘制固定的颜色,绘制ARGB,每个的值在0~225
drawARGB(int a, int r, int g, int b)
//去绘制一个颜色,一个十六进制的Int类型值
drawColor(int color)
//和第一个方法一样,只是把第一个透明度的参数去掉了
drawRGB(int r, int g, int b)
//绘制颜色,但是要制定一个mode,该mode的作用是当有层叠的时候,如何显示图片做一个限定,比如:有A,B两个图片有重叠的位置,那么重叠的位置是显示A的部分还是显示B的部分,还是都不显示,设置这个方法后,里面有很多类型可以选择
drawColor(int color, PorterDuff.Mode mode)
  • 绘制形状
// 画圆 (圆心x0,圆心y0,半径,paint)
Canvas.drawCircle(100, 100, 50, mPaint) ;
// 画圆弧 RectF对象表明内切矩形的(left,top,right,bottom)
RectF rf = new RectF(100 ,100 ,200 ,200) ;
// 参数(rf,startAngle ,angle ,sweepAngle ,paint) sweepAngle表明是否显示圆弧三角形 angle画多少度
Canvas.drawArc(rf, 60, 30, true, mPaint) ;
//画椭圆 初始化RectF的参数是(left,top,right,bottom)
RectF rf = new RectF(100,100 ,200 ,250) ;
Canvas.drawOval(rf, mPaint) ;
// 画线
Canvas.drawLine(...) ;
// 画长方形 Rect 和RectF的区别?
// 精度不一样,Rect是使用int类型作为数值,RectF是使用float类型作为数值
Rect r = new Rect(10,10,50,50) 
canvas.drawRect(矩形)
// 画一个点
Canvas.drawPoint(23, 23, mPaint) ;
// 画很多点这里的float[] 表示{x0,y0,x1,y1,x2,y2,x3,y3.....}
Canvas.drawPoints(new float[]{10,11,10,12,10,13,10,14,10,15,10,16}, mPaint) ;
// 绘制圆角矩形 RectF是矩形的(left,top,right,bottom)
RectF rf = new RectF(100 ,100 ,200 ,200) ;
// 50表明x方向的半径,20表示y方向的半径
Canvas.drawRoundRect(rf, 50, 20, mPaint) ;
canvas.drawVertices(顶点)
// 画任意多边形
Path path = new Path() ;
path.moveTo(100, 100) ;
path.lineTo(200, 200) ;
path.lineTo(300, 200) ;
Canvas.drawPath(path, mPaint) ;
Path path = new Path() ;
path.addCircle(100, 100, 20, Path.Direction.CCW) ;
Canvas.drawPath(path ,mPaint);
//具体的参数什么的,去Google,Api瞄一眼就OK,博主这里不做过多介绍
  • 绘制图片
// 画bitmap对象
Canvas.drawBitmap(BitmapFactory.decodeResource(mContext.getResources(), R.drawable.bg),100, 100, mPaint) ;
//通过Matrix对象去处理Bitmap,
Matrix m = new Matrix() ;
m.postScale(2, 2) ;
m.postRotate(60) ;
mCanvas.drawBitmap(BitmapFactory.decodeResource(mContext.getResources(), R.drawable.bg), m, mPaint) ;
canvas.drawPicture (图片)
  • 绘制文字
canvas.drawText("suan", 100, 100, paint);  
canvas.drawText(new char [] {'s','u','a','n','s','u','a','n'}, 2, 3, 100, 100, paint);  
canvas.drawText("suansuan", 2, 4, 100, 100, paint); //含头不含尾  

4、绘图技巧

我们的Canvas有上述的draw的方法,看起来足够我们在开发当中使用了,但是真正的使用起来,却感到有点乏力。为了开发者可用更加灵活方便使用转换的操作,Google官方还专门提供了一种类似于游戏存档的机制,就是canvas.save(),canvas.restore(),不过在了解,回档之前,我们还得熟悉一样东西,那就是我们的画布是可以做一些操作的,比如rorate、scale、translate、skew等效果。这些效果不是针对画出来的东西,而是针对画布而言的
这里写图片描述

下面看看代码 我想大家就知道是怎么回事了
        ImageView imageView = (ImageView) findViewById(R.id.image);
        Bitmap bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        Paint paint = new Paint();
        canvas.save();
        //原始
        canvas.drawARGB(255, 139, 197, 186);
        paint.setColor(Color.parseColor("#FFFF00"));
        canvas.drawRect(0,0,50,50,paint);
        //平移
        canvas.translate(50,50);
        paint.setColor(Color.parseColor("#00FFFF"));
        canvas.drawRect(0,0,50,50,paint);
        //旋转
        canvas.save();          //因为在旋转会影响后面的视图内容,所以在这里进行save
        canvas.translate(50,50);//先平移,如果不平移的话,容易遮盖
        canvas.rotate(120f);
        paint.setColor(Color.parseColor("#0000FF"));
        canvas.drawRect(0,0,50,50,paint);
        canvas.restore();       //回到旋转以前的视图
        //缩放
        canvas.translate(50,50);//先平移,如果不平移的话,容易遮盖
        canvas.scale(0.5f, 0.5f);
        paint.setColor(Color.parseColor("#FF00FF"));
        canvas.drawRect(0,0,50,50,paint);
        //错切
        canvas.translate(50,50);//先平移,如果不平移的话,容易遮盖
        //float sx:将画布在x方向上倾斜相应的角度,sx为倾斜角度的tan值;
        //float sy:将画布在y轴方向上倾斜相应的角度,sy为倾斜角度的tan值;
        //注意,这里全是倾斜角度的tan值,比如我们打算在X轴方向上倾斜45度,tan45=1;
        canvas.skew(1, 0);
        paint.setColor(Color.parseColor("#FF00FF"));
        canvas.drawRect(0,0,50,50,paint);
        canvas.restore();
        imageView.setImageBitmap(bitmap);

我们的XML为

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_margin="20dip">

        <Button
            android:layout_width="0dip"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="onclick"
            android:text="add Button" />
    </LinearLayout>
</RelativeLayout>

: 有了上述的概念,我们现在来说一说Canvas的save和restore,save就是把当前画布的状态保存起来,大家可以理解成游戏的存档,然后当我们restore的时候我们就回去读上一次最近的存档,然后把画布置为上一次保存的状态,如果上一次没有保存,则会抛出异常。在这里的画布的状态是什么呢,比如我们把画布旋转以后,那我们的整个画布都是旋转过得,如果我们在这个基础上绘图,会以旋转之后的为参照,所以我们需要回到之前的。


5、图层的概念

大家可以把以一个Canvas理解成为一个栈,里面维护了很多的Layer(图层),一般情况的时候,我们使用的canvas都是最底层的Layer进行操作,当我们使用saveLayerAlpha(),saveLayer()这两个方法进行入栈,当入栈以后,所有的操作都是作用在刚刚入栈的Layer,然后使用restore和restoreToCount这两个方法,进行出栈,出栈代表该图层已经绘制完毕,不是在绘制的时候不会显示之类的。大家来看一个Demo,就知道了
这里写图片描述

我们发现在我们开启图层的时候需要一个Flag,我们来看一下这些Falg都代表什么意思
FLAG作用适用方法
MATRIX_SAVE_FLAG只保存图层的matrix矩阵save,saveLayer
CLIP_SAVE_FLAG只保存大小信息save,saveLayer
HAS_ALPHA_LAYER_SAVE_FLAG表明该图层有透明度,和下面的标识冲突,都设置时以下面的标志为准saveLayer
FULL_COLOR_LAYER_SAVE_FLAG完全保留该图层颜色(和上一图层合并时,清空上一图层的重叠区域,保留该图层的颜色saveLayer
CLIP_TO_LAYER_SAVE_创建图层时,会把canvas(所有图层)裁剪到参数指定的范围,如果省略这个flag将导致图层开销巨大(实际上图层没有裁剪,与原图层一样大
ALL_SAVE_FLAG保存所有信息save,saveLayer
看完上述所说的Flag,我们再来看看我们的代码
        ImageView imageView = (ImageView) findViewById(R.id.image);
        Bitmap bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        Paint mPaint = new Paint();
        canvas.save();
        canvas.drawColor(Color.WHITE);
        canvas.translate(10, 10);
        mPaint.setColor(Color.RED);
        canvas.drawCircle(75, 75, 50, mPaint);
        //开启图层,该图层入栈
        canvas.saveLayerAlpha(0, 0, 200, 200, 0x88, Canvas.ALL_SAVE_FLAG);
        mPaint.setColor(Color.BLUE);
        canvas.drawCircle(125, 125, 50, mPaint);
        //该图层出栈
        canvas.restore();
        imageView.setImageBitmap(bitmap);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值