Android自定义控件系列——Canvas类全解析

Canvas

构造函数

//通常与setBitmap()配合使用
Canvas();
Canvas(Bitmap bitmap);	//Bitmap必须是mutable可变化的

通用API

setBitmap(Bitmap bitmap);	 //设置可变化的位图通常用在获取一张Bitmap后通过Canvas处理一下
getDensity();				//获取与设置画布密度,默认为Bitmap的密度或者DENSITY_NONE
setDensity(int density); 
getHeight(); 				//获取Canvas的高与宽
getWidth(); 				
isHardwareAccelerated();	 //判断当前Canvas是否开启了硬件加速
isOpaque(); 				//判断是否支持透明度
getDrawFilter(); 			//获取与设置DrawFilter
setDrawFilter(DrawFilter filter); 
//获取Bitmap的最大宽高,避免出现"Bitmap too large to be uploaded into a texture (4405x9705, max=4096x4096)."错误
//原因:开启硬件加速时GPU对openglRender有一个限制,不同手机限制不同,而这个限制阈值就是通过这个两个方法来获取的
getMaximumBitmapHeight();	
getMaximumBitmapWidth(); 

补充:DrawFilter

DrawFilter
	PaintFlagsDrawFilter
public PaintFlagsDrawFilter(int clearBits, int setBits);
//clearBits	清除Paint已经存在的指定flag
//setBits	设置Paint的flag

绘制相关API

drawLine

drawLine(float startX, float startY, float stopX, float stopY, Paint paint);
//startX,startY,stopX,stopY:开始点与结束点坐标
drawLines(float[] pts, Paint paint); 
drawLines(float[] pts, int offset, int count, Paint paint); 
//pts		要绘制的点数组 [x0 y0 x1 y1 x2 y2 ...]
//offset	要跳过的数组中的值数
//count		在跳过它们的“偏移”之后要处理的数组中的值的数量,必须大于2,因为线是由两个点决定,两个点由四个数值决定

drawPoint

drawPoint(float x, float y, Paint paint);
//x,y:绘制点的坐标
drawPoints(float[] pts, Paint paint);
drawPoints(float[] pts, int offset, int count, Paint paint); 
//pts		点集合
//offset	绘制开始跳过pts集合前面多少个数值。
//count		绘制从offset开始的count个数值点组成的坐标,count必须大于2。

drawRect

drawRect(float left, float top, float right, float bottom, Paint paint); 
//left,top,right,bottom		矩形的四个边与屏幕边界的距离。也可看做做左上角与右下角的坐标
drawRect(RectF rect, Paint paint); 
drawRect(Rect r, Paint paint);
//rect,r	通过一个RectF或者Rect的对象确定矩形的四个点

补充:RectF与Rect是矩形的辅助类,根据四个点构建一个矩形结构,两个精度不同而已

drawRoundRect

drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, Paint paint); 
//left,top,right,bottom		矩形的四个边与屏幕边界的距离。也可看做做左上角与右下角的坐标
//rx,ry		圆角的椭圆的X,y轴半径
drawRoundRect(RectF rect, float rx, float ry, Paint paint);
//rect	通过一个RectF的对象确定矩形的四个点

drawCircle

drawCircle(float cx, float cy, float radius, Paint paint);
//cx,cy		圆心坐标
//radius	圆半径

drawOval

drawOval(float left, float top, float right, float bottom, Paint paint) 
//left,top,right,bottom		矩形的四个边与屏幕边界的距离。也可看做做左上角与右下角的坐标
drawOval(RectF oval, Paint paint) 
//oval	通过一个RectF的对象确定矩形的四个点

drawArc

drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint); 
drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint paint);
//left,top,right,bottom		矩形的四个边与屏幕边界的距离。也可看做做左上角与右下角的坐标
//startAngle	弧开始角度
//sweepAngle	弧经历角度
//useCenter		是否有弧的两边,True有两边,False只有一条弧

drawPath

drawPath(Path path, Paint paint);

drawText

​ 绘制水平方向文字,或者是指定字符串中的一段文字

drawText(String text, float x, float y, Paint paint);
drawText(CharSequence text, int start, int end, float x, float y, Paint paint);
drawText(char[] text, int index, int count, float x, float y, Paint paint);
drawText(String text, int start, int end, float x, float y, Paint paint);
//x,y		绘制文字的起始点,位于文字的左下角
//start,end	绘制文字中的起始与结束index
//count		绘制文字的个数

drawTextOnPath

​ 沿路径绘制文字

drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint);
drawTextOnPath(char[] text, int index, int count, Path path, float hOffset, float vOffset, Paint paint);
//index			绘制文字中的起始index
count		绘制文字的个数
//hOffset,vOffset	代表与路径起始点的水平,垂直偏移距离

drawPosText

​ 依据每个坐标绘制每个文字

drawPosText(char[] text, int index, int count, float[] pos, Paint paint);
drawPosText(String text, float[] pos, Paint paint);
//index		绘制文字中的起始index
//count		绘制文字的个数
//pos   	每个字体的位置,每两个数字一组确定一个文字的坐标点

drawRGB

drawRGB(int r, int g, int b);
drawARGB(int a, int r, int g, int b);

drawColor

​ 绘制颜色,单纯的对画布进行颜色处理,默认PorterDuff.Mode为SRC_OVER模式

drawColor(int color);
drawColor(int color, PorterDuff.Mode mode);

drawBitmap

//对一个bitmap进行矩阵变换绘制
drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint);
//对图片裁剪后放大缩小显示在指定的区域中
drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint);
//src 	指定bitmap裁截区域,null则不裁剪bitmap
//dst 	裁剪后的bitmap在canvas中显示的区域大小,src通过放大缩小适应dst区域
drawBitmap(Bitmap bitmap, float left, float top, Paint paint);
drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint);

drawBitmapMesh

​ 绘制扭曲位图,应用:拉窗帘、Mac关闭网页吸入效果等

drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors, int colorOffset, Paint paint);
//meshWidth   横向上把原位图划分的格数
//meshHeight  纵向上把原位图划分的格数
//verts   	  长度为 (meshWidth+1) * (meshHeight+1) * 2 + vertOffset的数组,记录了扭曲后位图各顶点(网格线交点)位置,每两个数值表示一个坐标
//vertOffset  控制verts数组从第几个数组元素开始对bitmap进行扭曲
//colors  	  作用于上面的颜色数组,一般为null,长度为(meshWidth+1) * (meshHeight+1) + colorOffset
//colorOffset 控制colors数组从第几个数值开始

drawVertices

​ 绘制扭曲位图,是drawBitmapMesh()方法的通用格式,也称为更加通用版

drawVertices(Canvas.VertexMode mode, int vertexCount, float[] verts, int vertOffset, float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices, int indexOffset, int indexCount, Paint paint);

drawPicture

​ 绘制图片,硬件加速开启后失效

//Picture在android.graphics.Picture包中,相对于Drawable和Bitmap而言小巧很多,因为它存储的不是实际像素,而仅仅记录了每个绘制的过程
drawPicture(Picture picture); 
drawPicture(Picture picture, RectF dst); 
drawPicture(Picture picture, Rect dst);

Picture相关

//开始记录绘制过程
Canvas beginRecording(int width, int height)
//静态方法,从输入流创建一个Pictrue对象
static Picture createFromStream(InputStream stream)
//在canvas上画这个picture对象
void draw(Canvas canvas)
//结束录制绘制过程
void endRecording()
//获取宽高
int getHeight() 
int getWidth()
//将绘制结果写到输出流中
void writeToStream(OutputStream stream)
......

PictureDrawable相关

​ PictureDrawable在android.graphics.drawable.PictureDrawable中,它是从Drawable类继承而来的

//构造方法从Picture对象中实例化
PictureDrawable(Picture picture)
//绘制到Canvas
void draw(Canvas canvas)
//获取透明度级别
int getOpacity()
//从PictureDrawable转为Picture
Picture getPicture()
//设置透明级别
void setAlpha(int alpha)
......

案例

//一个高效绘制自定义View的例子模板:
Picture picture = new Picture();
Canvas canvas = picture.beginRecording(300, 500);
//canvas.drawBitmap();
//等等一堆画线画字画图操作
//这些操作都是基于Picture返回的canvas的,切记!!!!
picture.endRecording();

PictureDrawable pictureDrawable = new PictureDrawable(picture);
//viewCanvas是自定义View中onDraw方法的形参,切记!!!
pictureDrawable.draw(viewCanvas) ;  

小结

​ Picture可以记录我们Canvas上每个绘制操作,最后统一回放每个绘图操作,这些功能Bitmap也能实现
​ 但是Picture只是记录了我们绘图得操作而不是绘制后的像素结果而不是Bitmap等渲染结果,所以存储大小比Bitmap要小得多,同时渲染速度也比Bitmap要快

切割区域相关API

​ 所有区域切割相关的方法被调运后除过调用save、restore处理可以恢复原样Canvas以外该操作是不可逆的

clipPath

​ 依据路径和区域方式切割画布

clipPath(Path path);
clipPath(Path path, Region.Op op);	//已过时

补充:Region类介绍

/**
*构造方法
*/
//创建一个空区域
public Region();
//复制一个region区域
public Region(Region region);
//创建一个指定范围的矩形区域 
public Region(Rect r);
//创建一个指定顶点的矩形区域
public Region(int left, int top, int right, int bottom);

/**
*set方法.注意:调运set系列方法后原来Region的区域范围会被该set冲掉
*/
//设空Region区域,类似reset操作
public void setEmpty();
//用新区域来填充原来的区域
public boolean set(Region region);
//利用矩形区域填充区域
public boolean set(Rect r);
//利用矩形区域填充区域
public boolean set(int left, int top, int right, int bottom);
//根据路径的区域与某区域的交集构造出新的不规则区域
public boolean setPath(Path path, Region clip);
    
/**
*判断方法
*/
//判断该区域是否为空
public native boolean isEmpty();
//判断区域是否是一个矩阵  
public native boolean isRect();
//判断区域是否是多个矩阵组合
public native boolean isComplex();
    
/**
*边界获取方法
*/
public Rect getBounds();   
public boolean getBounds(Rect r);   
public Path getBoundaryPath();  
public boolean getBoundaryPath(Path path);   
    
/**
*否包含某点和是否相交判断方法
*/
//是否包含某点
public native boolean contains(int x, int y);
//是否包含某矩阵  
public boolean quickContains(Rect r); 
//是否没有包含某矩阵 
public native boolean quickContains(int left, int top, int right, int bottom); 
//是否没和该矩阵相交
public boolean quickReject(Rect r);  
public native boolean quickReject(int left, int top, int right, int bottom);  
public native boolean quickReject(Region rgn);
    
/**
*平移变换方法
*/
public void translate(int dx, int dy);   
public native void translate(int dx, int dy, Region dst);
    
/**
*组合方法,都与Op有关
*/
public final boolean union(Rect r);   
public boolean op(Rect r, Op op); 
public boolean op(int left, int top, int right, int bottom, Op op);   
public boolean op(Region region, Op op);   
public boolean op(Rect rect, Region region, Op op);

/**
*Region.Op的参数
*/
public enum Op {
    //最终组合区域为region1与region2不同的区域
    DIFFERENCE(0),
    //最终组合区域为region1与region2相交的区域   
    INTERSECT(1),
    //最终组合区域为region1与region2组合在一起的所有区域
    UNION(2),
    //最终组合区域为region1与region2相交以外的区域
    XOR(3),
    //最终组合区域为region2与region1不同的区域 
    REVERSE_DIFFERENCE(4),
    //最终组合区域为region2的区域 
    REPLACE(5);

    Op(int nativeInt) {
        this.nativeInt = nativeInt;
    }
    public final int nativeInt;
}

clipRect

​ 以矩形方式切割画布

clipRect(Rect rect, Region.Op op);
clipRect(RectF rect, Region.Op op);
clipRect(int left, int top, int right, int bottom);
clipRect(float left, float top, float right, float bottom);
clipRect(RectF rect);
clipRect(float left, float top, float right, float bottom, Region.Op op);
clipRect(Rect rect);

clipRegion

​ 以Region的区域方式切割画布

clipRegion(Region region);
clipRegion(Region region, Region.Op op);

clipBounds

​ 获取边界宽高等数据

//默认整个Canvas的范围
getClipBounds();
//Rect指定范围的数据
getClipBounds(Rect bounds);

quickReject

​ 判断是否没和某个指定区域相交,Region中也有类似方法,只是这里涉及Canvas.EdgeType

quickReject(float left, float top, float right, float bottom, Canvas.EdgeType type);
quickReject(Path path, Canvas.EdgeType type);
quickReject(RectF rect, Canvas.EdgeType type);

​ 补充:Canvas.EdgeType值介绍

public enum EdgeType {
    //边缘处类型为四舍五入最接近黑白即可
    BW(0),  
    //考虑抗锯齿时边缘处类型四舍五入
    AA(1);
    EdgeType(int nativeInt) {
        this.nativeInt = nativeInt;
    }
    public final int nativeInt;
}

变换方法相关API

translate

translate(float dx, float dy);
//dx,dy   水平,垂直平移距离,向右,下为正

scale

scale(float sx, float sy);
scale(float sx, float sy, float px, float py);
//sx,sy    水平,垂直伸缩比例。
//px,py    水平,垂直伸缩参考点,默认为Canvas的0点

rotate

rotate(float degrees);
rotate(float degrees, float px, float py);
//degrees  旋转度数,顺时针旋转为正
//px,py    旋转中心x坐标,默认为Canvas的0点

skew

skew(float sx, float sy);
//sx,sy    x,y方向倾斜的角度,sx,sy为倾斜角度的tan值

其他

concat(Matrix matrix);
getMatrix(Matrix ctm); 
getMatrix();
setMatrix(Matrix matrix);

图层与状态相关API

save

//保存当前canvas状态
save();
//保存canvas的多少种状态,从当前状态开始计算
save(int saveFlags); 
//获取canvas的多少种状态,从当前状态开始计算
getSaveCount();

restore

//恢复Canvas到之前状态
restore();
restoreToCount(int saveCount);

saveLayer

​ 和save方法类似,但具有离屏缓冲能力(通过它save后相当于新起一个offscreen bitmap,当我们在该offscreen bitmap上绘制一堆后调运restore()时才会将我们在offscreen bitmap上绘制的东西画回Canvas上)。性能消耗较高

saveLayer(RectF bounds, Paint paint, int saveFlags); 
saveLayer(RectF bounds, Paint paint); 
saveLayer(float left, float top, float right, float bottom, Paint paint); 
saveLayer(float left, float top, float right, float bottom, Paint paint, int saveFlags); 
saveLayerAlpha(RectF bounds, int alpha, int saveFlags); 
saveLayerAlpha(RectF bounds, int alpha); 
saveLayerAlpha(float left, float top, float right, float bottom, int alpha, int saveFlags); 
saveLayerAlpha(float left, float top, float right, float bottom, int alpha); 

​ 补充:

//View以一般方式绘制,不使用离屏缓冲,默认方式
LAYER_TYPE_NONE
//View如果开启了硬件加速则会被绘制到一个硬件纹理中,否则类同LAYER_TYPE_SOFTWARE模式
LAYER_TYPE_HARDWARE
//View被绘制到一个Bitmap中
LAYER_TYPE_SOFTWARE

​ 案例:自定义View进行动画或者渐变等特效操作时建议通过View的setLayerType()方法设置为View.LAYER_TYPE_HARDWARE,操作完成后再设置为View.LAYER_TYPE_NONE,因为这样可以提升绘制效率,不会再次进行无用绘制

​ 多次改变View的alpha、x、y、translationX、translationY、scaleX、scaleY、pivotX、pivotY、rotation、rotationX、rotationY等属性值时其实就是间接操作layer,所以你会觉得动效卡顿

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值