Android中View的绘制二

一,文字的高度测量和计算

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);

三,Canvas的范围裁切

1,Canvas.clipRect(),在这个范围内的可以有内容
2,Canvas.clipPath(),这个方法裁切之后后又毛边,无法解决
3,Canvas.clipOutRect()/Canvas.clipOutPath(),裁切内容的反过来的剩余

四,Canvas的几何变换

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);

五,Matrix的几何变换

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

六,Camera

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);

7,Canvas.rotate

rotate旋转默是以(0,0)为中心旋转

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章