1.第一种方式 (计算出来的文字的高度超级精确)
//1,这种方式计算出来的文字的高度超精确
Rect rect = new Rect();
paint.getTextBounds("ababj", 0, "ababj".length(), rect);
int offset = (rect.top + rect.bottom) / 2;
canvas.drawText("abab", getWidth() / 2, getHeight() / 2 - offset, paint);
其中offset就是上下的偏移量,高度减去offset,得出的文字高度非常的精确
2.第二种方式 (这种方式计算出来的文字高度稳定,不会出现跳动,动画稳定)
//2,这种方式计算出来的文字高度稳定,不会出现跳动,动画稳定
Paint.FontMetrics fontMetrics = new Paint.FontMetrics();
paint.getFontMetrics(fontMetrics);
float off = (fontMetrics.ascent + fontMetrics.descent) / 2;
canvas.drawText("1234", getWidth() / 2, getHeight() / 2 - off, paint);
3.文字其他的用法
paint.setStrokeCap(Paint.Cap.ROUND);//设置绘制的圆头
paint.setStyle(Paint.Style.FILL);//绘制文字要填充
paint.getFontSpacing() //获取的是两行的两个baseline之间的距离
paint.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "fz.ttf"));//设置字体
paint.setTextAlign(Paint.Align.CENTER);//设置文字水平居中
//设置文字对齐的,减去前面的间距
Rect rect = new Rect();
paint.getTextBounds("abab", 0, "abab".length(), rect);
Log.e("1234", rect.toString());//(9, 375 , 945, -28)
canvas.drawText("abab", -rect.left, 200, paint);//去除文字的左边空隙
float[] measuredWidth = new float[1];
//多行文字的绘制---index 是结束的那个字符的下一个-------折行
int index = paint.breakText
(
txt,//文本,文字内容
true,//正向测量,正序测量
getWidth(),//文字的最大的宽度,一般是View的宽度
measuredWidth//测量这一行字符的宽度结果放到这个数组里面
);
Log.e("1234", "=============index: " + index);
Log.e("1234", "=============getWidth(): " + getWidth());
Log.e("1234", "=============measuredWidth(): " + measuredWidth[0]);
canvas.drawText(txt, 0, index, 0, paint.getFontSpacing(), paint);
//得出的这个index是一行的文字个数
index = paint.breakText//一行的效果
(
txt,// 绘制文字
index,// 文字起始的位置
txt.length(),// 文字结束的位置
true,//正向测量,正序测量
getWidth() - UiUtils.dp2px(100),//文字最大的宽度,一般是View的宽度
measuredWidth //测量这一行字符的宽度结果放到这个数组里面
);
canvas.drawText(txt, oldIndex, oldIndex + index, 0, paint.getFontSpacing() * 2, paint);
1,Canvas.clipRect(),在这个范围内的可以有内容
2,Canvas.clipPath(),这个方法裁切之后后又毛边,无法解决
3,Canvas.clipOutRect()/Canvas.clipOutPath(),裁切内容的反过来的剩余
1,canvas.translate()
2,canvas.rotate()
3,canvas.scale()
4,canvas.skew()
绘制的理解:
存在两个坐标系,Canvas的坐标系和View的坐标系
canvas的第一次变换是以View的坐标系值为基准进行变换,canvas后面变换是以canvas之前的变换结果为为基准来进行变换的;
比如一张100*100大小的图片做如下的变换:
1,平移到(200,100)位置
2,然后旋转以图片的中心位置去旋转45度
下面这样才可能达到预期的效果:(按照 Canvas和View 2 个坐标系来理解,正着去写)
canvas.translate(200, 100);//第一次是以View的坐标系为准
canvas.rotate(45, 50, 50);//第二次绘制是按照canvas上一次以后的变换结果为基准((50,50)图片宽高一半)
canvas.drawBitmap(bitmap);
如果按照单个坐标系来理解,写的过程和实际想的过程完全反过来;
(就以View的坐标系为基准来理解,那样就会是非常的好理解)
脑海中想要的过程是(View的坐标系):
绘制===>>>平移到(200,100)===>>> 以(200+100/2,100+100/2)为中心旋转45
实际代码是View单坐标系理解,过程倒过来写,就会和脑海中的效果一模一样
实际代码中 反着去写(View的坐标系)
以(200+100/2,100+100/2)为中心旋转45 =>>> 平移到(200,100)=>>>剩下的再去绘制
代码如下,
canvas.rotate(45, 200 + 100 / 2, 100 + 100 / 2);//先写旋转
canvas.translate(200, 100);//再写平移,都是以View的坐标系为基准
canvas.drawBitmap(bitmap, 0, 0, paint);
perTranslate // perRotate // perScale // preSkew
比如一张100*100大小的图片做如下的变换:
1,平移到(200,100)位置
2,然后旋转以图片的中心位置去旋转45度
脑海中想要的过程是(View的坐标系):
绘制===>>>平移到(200,100)===>>> 以(200+100/2,100+100/2)为中心旋转45
当使用pre的时候,就是单坐标系(View坐标系)和脑海中想的过程是反着的,代码如下:
matrix.preRotate(45, 200 + bitmap.getWidth() / 2, 100 + bitmap.getHeight() / 2);//先旋转
matrix.preTranslate(200, 100);//再平移到(200,100)
canvas.drawBitmap(bitmap, matrix, paint);//最后绘制
postTranslate // postRotate // postScale // postSkew
当使用post的时候,就是单坐标系(View坐标系)和脑海中想的过程是一样的,代码如下:
matrix.postTranslate(200, 100);//先平移到(200,100)
matrix.postRotate(45, 200 + bitmap.getWidth() / 2, 100 + bitmap.getHeight() / 2);//再旋转
canvas.drawBitmap(bitmap, matrix, paint);//最后绘制
Matrix的实际变换过程
matrix.preTranslate(200, 100);//A
matrix.preRotate(45, bitmap.getWidth() / 2, bitmap.getHeight() / 2);//B
matrix.postTranslate(200, 300);//C ---往后加,实际是和想的反着
canvas.drawBitmap(bitmap, matrix, paint);
//matrix变换结果 B -> A -> C
//实际的执行结果是 C -> A -> B
rotate /// rotateX /// rotateY /// rotateZ
setLocation()
Camera camera = new Camera();
camera.rotateX(45);
camera.setLocation(0, 0, -8 * (getResources().getDisplayMetrics().density));//8*72 inch 兼容性适配
camera.applyToCanvas(canvas);
rotate旋转默是以(0,0)为中心旋转