Android自定义View(4) 《Canvas基本使用》
2021-08-29 本文已影响0人
非典型程序猿
概述
在Android中,我们经常会需要去绘制一些自己需要的控件,所以继承自View的自定义View就产生了。这篇文章主要介绍在View中的重要类,Canvas类的一些基本使用。
Canvas绘制背景
Canvas绘制背景主要有几个方法
/**
* 使用srcover-porterduff模式,用指定的颜色填充整个画布的位图(限于当前剪辑)
*
* @param color the color to draw onto the canvas
*/
public void drawColor(@ColorInt int color) {
super.drawColor(color);
}
/**
* 使用srcover-porterduff模式,用指定的颜色填充整个画布的位图(限于当前剪辑)
*
* @param color the {@code ColorLong} to draw onto the canvas. See the {@link Color}
* class for details about {@code ColorLong}s.
* @throws IllegalArgumentException if the color space encoded in the {@code ColorLong}
* is invalid or unknown.
*/
public void drawColor(@ColorLong long color){
super.drawColor(color, BlendMode.SRC_OVER);
}
/**
* 使用指定的颜色和porter duff xfermode填充整个画布的位图(仅限于当前剪辑)。
*
* @param color the color to draw onto the canvas
* @param mode the porter-duff mode to apply to the color
*/
public void drawColor(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
super.drawColor(color, mode);
}
/**
* 使用指定的颜色和blendmode填充整个画布的位图(仅限于当前剪辑)。
*
* @param color the color to draw onto the canvas
* @param mode the blendmode to apply to the color
*/
public void drawColor(@ColorInt int color, @NonNull BlendMode mode) {
super.drawColor(color, mode);
}
/**
* 使用指定的颜色和blendmode填充整个画布的位图(仅限于当前剪辑)。
*
* @param color the {@code ColorLong} to draw onto the canvas. See the {@link Color}
* class for details about {@code ColorLong}s.
* @param mode the blendmode to apply to the color
* @throws IllegalArgumentException if the color space encoded in the {@code ColorLong}
* is invalid or unknown.
*/
public void drawColor(@ColorLong long color, @NonNull BlendMode mode) {
super.drawColor(color, mode);
}
画布的平移
一般采用下面的方法进行canvas的平移
/**
* Preconcat the current matrix with the specified translation
*
* @param dx The distance to translate in X
* @param dy The distance to translate in Y
*/
public void translate(float dx, float dy) {
if (dx == 0.0f && dy == 0.0f) return;
nTranslate(mNativeCanvasWrapper, dx, dy);
}
这个方法可以将canvas的参考坐标平移,并不是平移之前已经绘制的内容,看下面一个例子大家就明白了,代码步骤是这样
- 绘制一个矩形
- 平移画布
- 再绘制一个矩形
代码如下
@Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
Log.d(TAG,"onDraw");
// 设置画笔的宽度
paint.setStrokeWidth(5f);
// 设置画笔的颜色
paint.setColor(Color.RED);
// 设置画笔的Style
paint.setStyle(Paint.Style.STROKE);
// 绘制一个矩形
canvas.drawRect(rectF,paint);
// 平移画布
canvas.translate(100,100);
// 绘制矩形
rectF = new RectF(width/2-300,height/2-150,width/2+300,height/2+150);
canvas.drawRect(rectF,paint);
}
运行结果是这样的
device-2021-08-29-185700.png
明白了吧,canvas只是你绘制时的一个图层而已,当你平移之后,并不影响之前已经绘制过的内容,所以在使用平移画布时请记得这点。
Canvas的裁剪,状态的保存和恢复
1.画布的裁剪
在学习裁剪之前,需要先搞清楚一个概念,这里画布的裁剪的意义与我们所理解的裁剪纸张的意义是不一样的,这里的裁剪好比你原本可以在一张完整的纸上进行绘制,裁剪后,就好像你的纸张被一张透明的玻璃盖住,中间你裁剪的部分就是空心的,可以往下面的纸张上继续画东西,其余部分则无法绘制,你只能看到之前绘制的内容,你如果裁剪出是一个圆形,那么你就是在这个圆中绘制你的内容,但是这并不影响显示你之前已经在纸上绘制出来的内容.
非常重要的点
裁剪是不可逆的 ! ! !
裁剪是不可逆的 ! ! !
裁剪是不可逆的 ! ! !
所以我们在使用裁剪时如果需要恢复,是必须要结合画布的保存和恢复一起使用的.裁剪使用的方法主要有以下几种
还要注意一点 使用裁剪时需要关闭硬件加速
setLayerType(LAYER_TYPE_SOFTWARE,null);
- clipOutRect()系列的函数,主要用来裁剪出一个矩形之外的部分
- clipRect()系列的函数,主要用来裁剪出一个矩形
- clipOutPath()系列的函数,主要用来裁剪出一个路径外的部分,一般是封闭的图形
- clipPath()系列的函数,主要用来裁剪出一个路径内的部分,一般为封闭图形
2.画布的状态保存与恢复
- 保存
int save() - 恢复
void restore() - 恢复到指定状态
void restoreToCount(int saveCount)
这里我们结合一个具体的例子来进行说明,例子的绘制步骤是这样的 - 1.给Canvas一个绿色背景
- 2.保存Canvas状态
- 3.在中心裁剪出一个矩形
- 4.在裁剪后的Canvas中加入灰色背景色
- 5.恢复画布状态
- 6.在恢复后的Canvas上画一个裁剪范围之外的蓝色的矩形框
好了我们开始写代码,代码也很简单
@Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
Log.d(TAG,"onDraw");
// 设置画笔的宽度
paint.setStrokeWidth(10f);
// 设置画笔的颜色
paint.setColor(Color.BLUE);
// 设置画笔的Style
paint.setStyle(Paint.Style.STROKE);
// 绘制背景色绿色
canvas.drawColor(Color.GREEN);
// 保存此时画布状态
int saveCount = canvas.save();
// 在画布中间裁剪出一个矩形
RectF rectF = new RectF(width/2-300,height/2-150,width/2+300,height/2+150);
canvas.clipRect(rectF);
// 绘制灰色背景方便观察
canvas.drawColor(Color.GRAY);
// 恢复画布状态,即裁剪之前
canvas.restoreToCount(saveCount);
// canvas.restore(); 恢复至上一个保存状态,这里和canvas.restoreToCount(saveCount)效果是一致的,择一调用即可。
// 恢复后绘制一个矩形
RectF rectB = new RectF(20,20,width-20,height-20);
canvas.drawRect(rectB,paint);
}
运行结果如下
device-2021-08-29-200319.png
为了验证我们的Canvas恢复是有效的,我们把恢复的代码注释掉,像这样
// 恢复画布状态,即裁剪之前
// canvas.restoreToCount(saveCount);
运行后变成了这样
device-2021-08-29-200553.png
我们最后绘制的蓝色矩形框没了,所以裁剪后在裁剪范围外绘制的内容是无效的,但是裁剪前绘制的内容是不影响显示的,所以这样可以理解裁剪时类似透明玻璃层的概念了吧
总结
Canvas的背景绘制,平移,状态保存和恢复就整理到这里了,下篇总结一下视图动画~