Android自定义View——Canvas图形/图片/文字绘制学习笔记

Posted by Csming on 2017-02-10

Canvas简介

Canvas成为画布;可以在上面绘制任何图案,是安卓平台2D图形绘制的基础

有两大特点:1.可操作性强;2.比较难用(组合操作)

常用操作

  • **绘制颜色:**drawColor, drawRGB, drawARGB;使用单一颜色填充整个画布
  • **绘制基本形状:**drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc;依次为 点、线、矩形、圆角矩形、椭圆、圆、圆弧
  • **绘制图片:**drawBitmap, drawPicture;绘制位图和图片
  • **绘制文本:**drawText, drawPosText, drawTextOnPath;依次为 绘制文字、绘制文字时指定每个文字位置、根据路径绘制文字
  • **绘制路径:**drawPath;绘制路径,绘制贝塞尔曲线等
  • **顶点操作:**drawVertices, drawBitmapMesh;通过对顶点操作可以使图像形变,drawVertices直接对画布作用、 drawBitmapMesh只对绘制的Bitmap作用
  • **画布裁剪:**clipPath, clipRect;设置画布的显示区域
  • **画布快照:**save, restore, saveLayerXxx, restoreToCount, getSaveCount;依次为 保存当前状态、 回滚到上一次保存的状态、 保存图层状态、 回滚到指定状态、 获取保存次数
  • **画布变换:**translate, scale, rotate, skew;依次为 位移、缩放、 旋转、错切
  • **Matrix(矩阵):**getMatrix, setMatrix, concat;实际上画布的位移,缩放等操作的都是图像矩阵Matrix, 只不过Matrix比较难以理解和使用,故封装了一些常用的方法。

Canvas详解

使用Canvas绘制基本图形

  • 绘制颜色
1
canvas.drawColor(Color.BLUE); //绘制蓝色
  • 创建画笔
1
2
3
4
5
6
Paint mPaint = new Paint();
private void initPaint(){
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeWidth(10f);
}
  • **绘制点
1
2
3
4
5
6
canvas.drawPoint(200, 200, mPaint);     //在坐标(200,200)位置绘制一个点
canvas.drawPoints(new float[]{ //绘制一组点,坐标位置由float数组指定
500,500,
500,600,
500,700
},mPaint);
  • 绘制直线
1
2
3
4
5
canvas.drawLine(300,300,500,600,mPaint);    // 在坐标(300,300)(500,600)之间绘制一条直线
canvas.drawLines(new float[]{ // 绘制一组线 每四数字(两个点的坐标)确定一条线
100,200,200,200,
100,300,200,300
},mPaint);
  • 绘制矩形
1
2
3
4
5
6
7
8
9
10
// 第一种
canvas.drawRect(100,100,800,400,mPaint);

// 第二种
Rect rect = new Rect(100,100,800,400);
canvas.drawRect(rect,mPaint);

// 第三种
RectF rectF = new RectF(100,100,800,400);
canvas.drawRect(rectF,mPaint);
  • **Rect与RectF的区别:**两者最大的区别就是精度不同,Rect是int(整形)的,而RectF是float(单精度浮点型)的

  • 绘制圆角矩形

1
2
3
4
5
6
// 第一种
RectF rectF = new RectF(100,100,800,400);
canvas.drawRoundRect(rectF,30,30,mPaint);

// 第二种
canvas.drawRoundRect(100,100,800,400,30,30,mPaint);
  • 绘制椭圆
1
2
3
4
5
RectF rectF = new RectF(100,100,800,400);
canvas.drawOval(rectF,mPaint);

// 第二种
canvas.drawOval(100,100,800,400,mPaint);
  • 绘制圆
1
canvas.drawCircle(500,500,400,mPaint);  // 绘制一个圆心坐标在(500,500),半径为400 的圆。
  • 绘制圆弧
1
2
3
4
5
6
7
8
9
// 第一种
public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint){}

// 第二种
public void drawArc(float left, float top, float right, float bottom, float startAngle,
float sweepAngle, boolean useCenter, @NonNull Paint paint) {}
//startAngle // 开始角度
//sweepAngle // 扫过角度
//useCenter // 是否使用中心

Paint

基本形状由Canvas确定,但绘制出来的颜色,具体效果则由Paint确定

  • 设置画笔样式
1
2
3
4
5
mPaint.setStyle(Paint.Style.FILL);  //设置画笔模式为填充

//STROKE //描边
//FILL //填充
//FILL_AND_STROKE //描边加填充
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Paint paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(40); //为了实验效果明显,特地设置描边宽度非常大

// 描边
paint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(200,200,100,paint);

// 填充
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(200,500,100,paint);

// 描边加填充
paint.setStyle(Paint.Style.FILL_AND_STROKE);
canvas.drawCircle(200, 800, 100, paint);

绘制图片

drawPicture

A Picture records drawing calls (via the canvas returned by beginRecording) and can then play them back into Canvas (via draw(Canvas) or drawPicture(Picture)).For most content (e.g. text, lines, rectangles), drawing a sequence from a picture can be faster than the equivalent API calls, since the picture performs its playback without incurring any method-call overhead.

  • Picture录制Canvas中绘制的内容
    把Canvas绘制点,线,矩形等诸多操作用Picture录制下来,下次需要的时候拿来就能用,使用Picture相比于再次调用绘图API,开销是比较小的
相关方法 简介
public int getWidth () 获取宽度
public int getHeight () 获取高度
public Canvas beginRecording (int width, int height) 开始录制 (返回一个Canvas,在Canvas中所有的绘制都会存储在Picture中)
public void endRecording () 结束录制
public void draw (Canvas canvas) 将Picture中内容绘制到Canvas中
public static Picture createFromStream (InputStream stream) (已废弃)通过输入流创建一个Picture
public void writeToStream (OutputStream stream) (已废弃)将Picture中内容写出到输出流中

eg:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 1.创建Picture
private Picture mPicture = new Picture();

---------------------------------------------------------------

// 2.录制内容方法
private void recording() {
// 开始录制 (接收返回值Canvas)
Canvas canvas = mPicture.beginRecording(500, 500);
// 创建一个画笔
Paint paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStyle(Paint.Style.FILL);

// 在Canvas中具体操作
// 位移
canvas.translate(250,250);
// 绘制一个圆
canvas.drawCircle(0,0,100,paint);

mPicture.endRecording();
}

---------------------------------------------------------------

// 3.在使用前调用(我在构造函数中调用了)
public Canvas3(Context context, AttributeSet attrs) {
super(context, attrs);

recording(); // 调用录制
}
  • 将Picture中的内容绘制出来可以有以下几种方法

1.使用Picture提供的draw方法绘制

2.使用Canvas提供的drawPicture方法绘制

1
2
3
4
5
public void drawPicture (Picture picture)

public void drawPicture (Picture picture, Rect dst)

public void drawPicture (Picture picture, RectF dst)

3.将Picture包装成PictureDrawable,使用PictureDrawable的draw方法绘制

1
2
3
4
5
6
// 包装成为Drawable
PictureDrawable drawable = new PictureDrawable(mPicture);
// 设置绘制区域 -- 注意此处所绘制的实际内容不会缩放
drawable.setBounds(0,0,250,mPicture.getHeight());
// 绘制
drawable.draw(canvas);

drawBitmap

  • 获取Bitmap方式
    **1.通过Bitmap创建:**复制一个已有的Bitmap(新Bitmap状态和原有的一致) 或者 创建一个空白的Bitmap(内容可改变)
    **2.通过BitmapDrawable获取:**从资源文件 内存卡 网络等地方获取一张图片并转换为内容不可变的Bitmap
    **3.通过BitmapFactory获取:**从资源文件 内存卡 网络等地方获取一张图片并转换为内容不可变的Bitmap

我们绘制Bitmap都是读取已有的图片转换为Bitmap绘制到Canvas上

  • BitmapFactory从不同位置获取Bitmap
1
Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(),R.raw.bitmap);

资源文件(assets)
Bitmap bitmap=null;
try {
InputStream is = mContext.getAssets().open(“bitmap.png”);
bitmap = BitmapFactory.decodeStream(is);
is.close();
} catch (IOException e) {
e.printStackTrace();
}

内存卡文件

1
Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/bitmap.png");

网络文件

1
2
3
4
// 获取网络输入流
...
Bitmap bitmap = BitmapFactory.decodeStream(is);
is.close();
  • 绘制Bitmap
1
2
3
4
5
6
7
8
9
// 第一种
public void drawBitmap (Bitmap bitmap, Matrix matrix, Paint paint)

// 第二种
public void drawBitmap (Bitmap bitmap, float left, float top, Paint paint)

// 第三种
public void drawBitmap (Bitmap bitmap, Rect src, Rect dst, Paint paint)
public void drawBitmap (Bitmap bitmap, Rect src, RectF dst, Paint paint)

eg:

1
canvas.drawBitmap(bitmap,new Matrix(),new Paint());

绘制文字

1
2
3
4
5
6
7
8
9
10
11
12
13
// 第一类
public void drawText (String text, float x, float y, Paint paint)
public void drawText (String text, int start, int end, float x, float y, Paint paint)
public void drawText (CharSequence text, int start, int end, float x, float y, Paint paint)
public void drawText (char[] text, int index, int count, float x, float y, Paint paint)

// 第二类
public void drawPosText (String text, float[] pos, Paint paint)
public void drawPosText (char[] text, int index, int count, float[] pos, Paint paint)

// 第三类
public void drawTextOnPath (String text, Path path, float hOffset, float vOffset, Paint paint)
public void drawTextOnPath (char[] text, int index, int count, Path path, float hOffset, float vOffset, Paint paint)
  • 分为三类:
    1.只能指定文本基线位置(基线x默认在字符串左侧,基线y默认在字符串下方)。
    2.可以分别指定每个文字的位置。
    3.是指定一个路径,根据路径绘制文字。

出处:http://www.gcssloop.com/customview/Canvas_BasicGraphics
http://www.gcssloop.com/customview/Canvas_PictureText