Android自定义控件系列——Canvas类全解析
Canvas构造函数//通常与setBitmap()配合使用Canvas();Canvas(Bitmap bitmap);//Bitmap必须是mutable可变化的通用APIsetBitmap(Bitmap bitmap);//设置可变化的位图通常用在获取一张Bitmap后通过Canvas处理一下getDensity();//获取与设置画布密度,默认为Bitmap的...
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,所以你会觉得动效卡顿
更多推荐
所有评论(0)