Android-CustomView Canvas
概念:
Canvas我们可以称之为画布,能够在上面绘制各种东西,是安卓平台2D图形绘制的基础,非常强大。
绘制颜色 drawColor, drawRGB, drawARGB 使用单一颜色填充整个画布
1canvas.drawColor(Color.BLUE); //绘制蓝色绘制基本形状 drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc 依次为 点、线、矩形、圆角矩形、椭圆、圆、圆弧
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354canvas.drawPoint(200, 200, mPaint); //在坐标(200,200)位置绘制一个点canvas.drawPoints(new float[]{ //绘制一组点,坐标位置由float数组指定500,500,500,600,500,700},mPaint);canvas.drawLine(300,300,500,600,mPaint); // 在坐标(300,300)(500,600)之间绘制一条直线canvas.drawLines(new float[]{ // 绘制一组线 每四数字(两个点的坐标)确定一条线100,200,200,200,100,300,200,300},mPaint);// 第一种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);// 第一种RectF rectF = new RectF(100,100,800,400);canvas.drawRoundRect(rectF,30,30,mPaint);// 第二种canvas.drawRoundRect(100,100,800,400,30,30,mPaint);// 矩形RectF rectF = new RectF(100,100,800,400);// 绘制背景矩形mPaint.setColor(Color.GRAY);canvas.drawRect(rectF,mPaint);// 绘制圆角矩形mPaint.setColor(Color.BLUE);canvas.drawRoundRect(rectF,700,400,mPaint);// 第一种RectF rectF = new RectF(100,100,800,400);canvas.drawOval(rectF,mPaint);// 第二种canvas.drawOval(100,100,800,400,mPaint);canvas.drawCircle(500,500,400,mPaint); // 绘制一个圆心坐标在(500,500),半径为400 的圆。// 第一种//userCenter 是否使用中心//false 画过的是弧区//true 画过的是带圆心的半圆弧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) {}绘制图片 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比较难以理解和使用,故封装了一些常用的方法。创建画布
要想绘制内容,首先需要先创建一个画笔,如下:123456789101112131415// 1.创建一个画笔private Paint mPaint = new Paint();// 2.初始化画笔private void initPaint() {mPaint.setColor(Color.BLACK); //设置画笔颜色mPaint.setStyle(Paint.Style.FILL); //设置画笔模式为填充mPaint.setStrokeWidth(10f); //设置画笔宽度为10px}// 3.在构造函数中初始化public SloopView(Context context, AttributeSet attrs) {super(context, attrs);initPaint();}
Canvas
位移(translate)
translate是坐标系的移动,可以为图形绘制选择一个合适的坐标系。 请注意,位移是基于当前位置移动,而不是每次基于屏幕左上角的(0,0)点移动,如下:12345678mPaint.setColor(Color.BLACK);canvas.translate(200,200);canvas.drawCircle(0,0,100,mPaint);// 在坐标原点绘制一个蓝色圆形mPaint.setColor(Color.BLUE);canvas.translate(200,200);canvas.drawCircle(0,0,100,mPaint);缩放(scale)
缩放提供了两个方法,如下:123456789101112131415public void scale (float sx, float sy)public final void scale (float sx, float sy, float px, float py)// 将坐标系原点移动到画布正中心canvas.translate(mWidth / 2, mHeight / 2);RectF rect = new RectF(0,-400,400,0); // 矩形区域mPaint.setColor(Color.BLACK); // 绘制黑色矩形canvas.drawRect(rect,mPaint);canvas.scale(0.5f,0.5f); // 画布缩放mPaint.setColor(Color.BLUE); // 绘制蓝色矩形canvas.drawRect(rect,mPaint);旋转(rotate)
旋转提供了两种方法:123public void rotate (float degrees)public final void rotate (float degrees, float px, float py)和缩放一样,第二种方法多出来的两个参数依旧是控制旋转中心点的。
默认的旋转中心依旧是坐标原点:
drawBitmap
通过BitmapFactory从不同位置获取Bitmap:
资源文件(drawable/mipmap/raw):
资源文件(assets):
内存卡文件:
网络文件:
既然已经获得到了Bitmap,那么就开始本文的重点了,将Bitmap绘制到画布上。
绘制Bitmap:
依照惯例先预览一下drawBitmap的常用方法:
绘制文本
|
|
drawText()
drawText(String text, float x, float y, Paint paint)
drawText() 是 Canvas 最基本的绘制文字的方法:给出文字的内容和位置, Canvas 按要求去绘制文字。
text 是文字内容,x 和 y 是文字的坐标。但需要注意:这个坐标并不是文字的左上角,而是一个与左下角比较接近的位置。大概在这里:
参数Y 时基线(baseline)
drawTextOnPath()
沿着一条 Path 来绘制文字。这是一个耍杂技的方法。
StaticLayout
Canvas.drawText() 只能绘制单行的文字,而不能换行。它:
- 不能在 View 的边缘自动折行
- 不能在换行符 \n 处换行
理解:StaticLayout 并不是一个 View 或者 ViewGroup ,而是 android.text.Layout 的子类,它是纯粹用来绘制文字的。 StaticLayout 支持换行,它既可以为文字设置宽度上限来让文字自动换行,也会在 \n 处主动换行。
1234567StaticLayout 的构造方法是 StaticLayout(CharSequence source, TextPaint paint, int width, Layout.Alignment align, float spacingmult, float spacingadd, boolean includepad),其中参数里:width 是文字区域的宽度,文字到达这个宽度后就会自动换行;align 是文字的对齐方向;spacingmult 是行间距的倍数,通常情况下填 1 就好;spacingadd 是行间距的额外增加值,通常情况下填 0 就好;includeadd 是指是否在文字上下添加额外的空间,来避免某些过高的字符的绘制出现越界。
setTextSize(float textSize)
|
|
setTypeface(Typeface typeface)
|
|
setFakeBoldText(boolean fakeBoldText)
是否使用伪粗体。
setStrikeThruText(boolean strikeThruText)
是否加删除线。
setUnderlineText(boolean underlineText)
是否加下划线。
setTextSkewX(float skewX)
设置文字横向错切角度。其实就是文字倾斜度的啦。
setLetterSpacing(float letterSpacing)
设置字符间距。默认值是 0。
setTextAlign(Paint.Align align)
设置文字的对齐方式。一共有三个值:LEFT CETNER 和 RIGHT。默认值为 LEFT。
范围裁切
Canvas.translate(float dx, float dy) 平移
Canvas.save() 和 Canvas.restore() 来及时恢复绘制范围,所以完整代码是这样的:
几何变化
Canvas.translate(float dx, float dy) 平移
1234canvas.save();canvas.translate(200, 0);canvas.drawBitmap(bitmap, x, y, paint);canvas.restore();Canvas.rotate(float degrees, float px, float py) 旋转
参数里的 degrees 是旋转角度,单位是度(也就是一周有 360° 的那个单位),方向是顺时针为正向; px 和 py 是轴心的位置。1234canvas.save();canvas.rotate(45, centerX, centerY);canvas.drawBitmap(bitmap, x, y, paint);canvas.restore();Canvas.scale(float sx, float sy, float px, float py) 放缩
参数里的 sx sy 是横向和纵向的放缩倍数; px py 是放缩的轴心。1234canvas.save();canvas.scale(1.3f, 1.3f, x + bitmapWidth / 2, y + bitmapHeight / 2);canvas.drawBitmap(bitmap, x, y, paint);canvas.restore();skew(float sx, float sy) 错切
参数里的 sx 和 sy 是 x 方向和 y 方向的错切系数。1234canvas.save();canvas.skew(0, 0.5f);canvas.drawBitmap(bitmap, x, y, paint);canvas.restore();
使用 Matrix 来做常见变换
Matrix 做常见变换的方式:
- 创建 Matrix 对象;
- 调用 Matrix 的 pre/postTranslate/Rotate/Scale/Skew() 方法来设置几何变换;
- 使用 Canvas.setMatrix(matrix) 或 Canvas.concat(matrix) 来把几何变换应用到 Canvas。
super.onDraw(canvas);
这个方法是空12345678910111213141516/ 在 View.java 的源码中,onDraw() 是空的// 所以直接继承 View 的类,它们的 super.onDraw() 什么也不会做public class View implements Drawable.Callback,KeyEvent.Callback, AccessibilityEventSource {.../*** Implement this to do your drawing.** @param canvas the canvas on which the background will be drawn*/protected void onDraw(Canvas canvas) {}...}
###