在自定義元件中,Paint類是一個很重要的類,主要包含顔色、文本、圖形樣式、位圖模式、濾鏡等幾個方面。Paint類的相關方法如下:
1、顔色是指繪圖時使用的顔色,在 Android 中顔色可以指定透明度,使用 16 進制來表示顔色
時,格式通常為#AARRGGBB,其中,AA 表示透明度、RR 表示紅色、GG 表示綠色、BB 表示藍色,
Color 類定義了顔色資訊,内置了常用顔色的 int 型常量,比如 Color.RED 是紅色,Color.BLUE 是
藍色……如果您習慣了 16 進制的顔色, Color 類的靜态方法 parseColor(String colorString)可以将 16進制顔色轉換成 Color 類型。需要注意的是,Android 的顔色都是 int 類型的,Color 類隻負責顔色的管理而不是代表某種顔色。
Paint 類中與顔色相關的方法有:
public native void setColor(int color);//設定顔色
public native void setAlpha(int a);//設定透明度,a 的範圍取 0~255 之間的整數
public void setARGB(int a,int r,int g,int b);//指定透明度、紅、綠、藍定義一種顔色
2、繪制文本時,可以指定文本的大小、對齊方式、文本樣式等屬性,文本樣式主要是為文本指定粗體、下劃線、删除線等修飾性屬性,主要說明下設定字型大小這個:
public native void setTextSize(float textSize);// 設定文本大小,機關是 px,這個和我們平時使用的字型機關 sp 不同,是以最好進行轉換,這個要注意。
比較麻煩的是繪制文字時,我們還要考慮字型的基本結構,字型的資訊使用 Paint.FontMetrics 類來表示,該類源碼如下:
public static class FontMetrics {
public float ascent;
public float bottom;
public float descent;
public float leading;
public float top;
}
從文字上了解可能比較晦澀,看下示意圖也許很容易找到答案:
簡單來說,常用字元的高度是 ascent 和 descent 的和,但是,一些特殊字元比如拼音的音調等則會延伸到 top 的位置。
baseline:基準點(綠色虛線所指);
ascent:baseline 之上至字元最高處的距離;
descent:baseline 之下至字元最低處的距離;
top:字元可達最高處到 baseline 的值,即 ascent 的最大值;
bottom:字元可達最低處到 baseline 的值,即 descent 的最大值。
leading:行間距,表示上一行字元的descent到該行字元的ascent之間的距離
根據世界範圍内已入案的使用語言中能夠标注在字元上方或者下方的除了類似的符号肯定是數不勝數的,一般情況下我們極少使用到類似的符号是以往往會忽略掉這些符号的存在,但是Android依然會在繪制文本的時候在文本外層留出一定的邊距,這就是為什麼 top和bottom總會比ascent和descent大一點的原因。而在TextView中我們可以通過xml設定其屬性 android:includeFontPadding="false"去掉一定的邊距值但是不能完全去掉。
要擷取 FontMetrics 對象,調用 Paint 類的 getFontMetrics()即可,而在 drawText()方法中,參數 y 就是 baseline 的值,因為 FontMetrics 類并沒有聲明 baseline 屬性,是以,我們需要通過下面的公式計算出來:
int baseline=(int) (viewHeight - fontMetrics.descent - fontMetrics.ascent) /2;
其中,viewHeight 是文字所在區域的高度。
下面自定義一個文本繪制的View
public class TextView1 extends View {
private static final String TEXT = "Android自定義";
private Paint paint;
public TextView1(Context context) {
super(context);
public TextView1(Context context, AttributeSet attrs) {
super(context, attrs);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.RED);
FontMetrics fontMetrics = paint.getFontMetrics();
Log.d("xmr", "ascent:" + fontMetrics.ascent);
Log.d("xmr", "top:" + fontMetrics.top);
Log.d("xmr", "leading:" + fontMetrics.leading);
Log.d("xmr", "descent:" + fontMetrics.descent);
Log.d("xmr", "bottom:" + fontMetrics.bottom);
public TextView1(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 将文字放在正中間
Rect textRect = this.getTextRect();
int viewWidth = getMeasuredWidth();
int viewHeight = getMeasuredHeight();
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
int x = (viewWidth - textRect.width()) / 2;
int y = (int) (viewHeight - fontMetrics.descent - fontMetrics.ascent) / 2;
canvas.drawText(TEXT, x, y, paint);
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Rect rect = getTextRect();
int textWidth = rect.width();
int textHeight = rect.height();
int width = measureWidth(widthMeasureSpec, textWidth);
int height = measureHeight(heightMeasureSpec, textHeight);
setMeasuredDimension(width, height);
/**
* 擷取文字所占的尺寸
*
* @return
*/
private Rect getTextRect() {
// 根據 Paint 設定的繪制參數計算文字所占的寬度
Rect rect = new Rect();
// 文字所占的區域大小儲存在 rect 中
paint.getTextBounds(TEXT, 0, TEXT.length(), rect);
return rect;
* 測量元件寬度
* @param widthMeasureSpec
* @param textWidth
* 文字所占寬度
private int measureWidth(int widthMeasureSpec, int textWidth) {
int mode = MeasureSpec.getMode(widthMeasureSpec);
int size = MeasureSpec.getSize(widthMeasureSpec);
int width = 0;
if (mode == MeasureSpec.EXACTLY) {
// 寬度為 match_parent 和具體值時,直接将 size 作為元件的寬度
width = size;
} else if (mode == MeasureSpec.AT_MOST) {
// 寬度為 wrap_content,寬度需要計算,此處為文字寬度
width = textWidth;
return width;
* 測量元件高度
* @param heightMeasureSpec
* @param textHeight
* 文字所占高度
private int measureHeight(int heightMeasureSpec, int textHeight) {
int mode = MeasureSpec.getMode(heightMeasureSpec);
int size = MeasureSpec.getSize(heightMeasureSpec);
int height = 0;
// 寬度為 match_parent 和具體值時,直接将 size 作為元件的高度
height = size;
// 高度為 wrap_content,高度需要計算,此處為文字高度
height = textHeight;
return height;
效果如下:
logcat輸出如下:
如圖我們得到了top,ascent,descent,bottom和leading的值,因為隻有一行文本是以leading恒為0。
從代碼中可以發現在我們繪制文本之前我們便可以擷取文本的FontMetrics屬性值,也就是說我們FontMetrics的這些值跟我們要繪制什麼文本是無關的,而僅與繪制文本Paint的size和typeface有關,我們來分别更改這兩個值看看效果:
paint.setTextSize(36);
如圖所示所有值都改變了,我們再為Paint設定一個typeface:
paint.setTypeface(Typeface.defaultFromStyle(Typeface.ITALIC));
3、圖形樣式包含繪制的圖形是空心樣式還是實心樣式,同時還能指定落筆和收筆時的筆觸效
果。繪制直線或折線時,圖形樣式能影響到一些繪制細節。
Paint 類與圖形樣式相關的方法有:
public void setStyle(Paint.Style style);//設定繪制的圖形是空心樣式還是實心樣式,預設為實心樣式,style 的可選值有:
public static enum Style{
FILL,
FILL_AND_STROKE,
STROKE
}
其中,FILL 表示實心樣式,對于閉合圖形來說,會用指定的顔色進行填充;STROKE 表
示空心樣式,繪制時隻有線條而無填充效果;FILL_AND_STROKE 表示同時使用實心樣
式和空心樣式。
public void setStrokeJoin(Paint.Join join)
當繪圖樣式為 STROKE 時,該方法用于指定線條連接配接處的拐角樣式,能使繪制的圖形
更加平滑。可選值如下:
public static enum Join {
BEVEL,
MITER,
ROUND
我們通過下圖來差別上面三個枚舉值(比較右上角即可) ,預設值為 MITER:
public void setStrokeCap(Paint.Cap cap)
該方法用于設定落筆時的樣式,控制我們的畫筆在離開畫闆時留下的最後一點圖形,可選值如下:
public static enum Cap {
BUTT,
ROUND,
SQUARE
我們通過下圖來差別上面三個枚舉值,預設值為 BUTT:
public native void setStrokeWidth(float width)
設定線條的寬度,注意是 float 類型,在 Android 中最細的線條不是 1,可以比 1 更小更細。
參考:
http://blog.csdn.net/abcdef314159/article/details/51720686