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)爲中心旋轉

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