前言
上一節,學會了Paint,Canvas的基本用法後,這一節,學習Paint的高級用法。還沒看過上一節的請點擊這裏:Android_2D繪圖的學習Paint,Canvas(一)。
一,文字的繪製
在做UI的時候,常常會繪製文字,Canvas繪製文字時,主要考慮到字體的寬度和高度問題。字體的寬度比較好理解,這裏我們主要考慮一下字體的高度。
先看一張圖,網上搜的:
這裏說明了在安卓中繪製字體時對於高度的劃分:top,ascent,baseLine,descent,bottom.有點類似我們剛開始學英語的時候的練習本。字體的高度我們取得是ascent到descent的距離。經過我測試,系統自帶的TextView中,繪製的背景高度爲top到bottom的距離。字體的起始座標點默認是baseLine中最左邊的一個點,可以通過調用Paint.setTextAlign(Paint.Align align)方法設置中間還是最右邊。
我們先來繪製一個正確的文字居中的一個效果:
代碼:
private Paint mPaint;
private String mText = "Android Paint學習";
public PaintView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setTextSize(TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 20, getResources()
.getDisplayMetrics()));
}
public PaintView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
// TODO Auto-generated constructor stub
}
public PaintView(Context context) {
this(context, null);
// TODO Auto-generated constructor stub
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//得到文字寬度
int textWidth = (int) mPaint.measureText(mText);
//得到文字高度
int textHeight = (int) (mPaint.descent() - mPaint.ascent());
// 設置View的高度和寬度爲字體的高度和寬度
widthMeasureSpec = MeasureSpec.makeMeasureSpec(textWidth,
MeasureSpec.EXACTLY);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(textHeight,
MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
//這裏減去了一個descent主要是畫筆畫文字的基準線爲baseLine,如果不減,就會出現底部有一部分看不到的情況
canvas.drawText(mText, 0, getHeight() - mPaint.descent(), mPaint);
}
明顯可以看出系統的TextView要高一點。注意top和ascent的值都是負值,所以在獲取高度時,是減去ascent。如果要像TextView一樣的高度的方法代碼:
FontMetrics fm = mPaint.getFontMetrics();
int textHeight = (int) (fm.descent - fm.top+2);
因爲Paint沒有top()這個方法所以我們用FontMetrics中的top屬性。
這裏參考了一篇博文:Android字體高度的研究講的很詳細的。
二,Paint.Cap
The Cap specifies the treatment for the beginning and ending of stroked lines and paths. The default is BUTT.
cap是帽子,覆蓋的意思,在畫筆中,就是指定邊緣點(畫筆第一點,和畫筆最後一點)的樣式。
一共有3種樣式:BUTT,ROUND,SQUARE.
我都以畫一段圓弧來說明,效果:
從左至右分別是:SQUARE,ROUND,BUTT一看圖,就瞭然了。
代碼:
mPaint.setColor(Color.RED);
mPaint.setStrokeWidth(2);
canvas.drawLine(0, 50, getWidth(), 50, mPaint);
mPaint.setStrokeWidth(30);
mPaint.setStyle(Style.STROKE);
mPaint.setAntiAlias(true);
mPaint.setColor(Color.BLACK);
mPaint.setStrokeCap(Cap.BUTT);
canvas.drawArc(new RectF(-getWidth() + 150, -getHeight() + 150,
getWidth() - 50, getHeight() - 50), 0, 50, false, mPaint);
mPaint.setStrokeCap(Cap.ROUND);
canvas.drawArc(new RectF(-getWidth() + 100, -getHeight() + 150,
getWidth() - 100, getHeight() - 50), 0, 50, false, mPaint);
mPaint.setStrokeCap(Cap.SQUARE);
canvas.drawArc(new RectF(-getWidth() + 50, -getHeight() + 150,
getWidth() - 150, getHeight() - 50), 0, 50, false, mPaint);
三,Paint.join
The Join specifies the treatment where lines and curve segments join on a stroked path. The default is MITER.
摘自官方文檔,就是說路徑在轉彎的時候指定其樣式。
一共有3種樣式:MITER,ROUND,BEVEL。
效果:
從左至右分別是:MITER,ROUND,BEVEL。
代碼:
mPaint.setStrokeWidth(40);
mPaint.setStyle(Style.STROKE);
mPaint.setStrokeJoin(Join.MITER);
Path path = new Path();
path.moveTo(0, 30);
path.lineTo(100, 30);
path.lineTo(100, 100);
canvas.drawPath(path, mPaint);
mPaint.setStrokeJoin(Join.ROUND);
Path path1 = new Path();
path1.moveTo(200, 30);
path1.lineTo(300, 30);
path1.lineTo(300, 100);
canvas.drawPath(path1, mPaint);
mPaint.setStrokeJoin(Join.BEVEL);
Path path2 = new Path();
path2.moveTo(400, 30);
path2.lineTo(500, 30);
path2.lineTo(500, 100);
canvas.drawPath(path2, mPaint);
四,Paint.FontMetrics
調用Paint.getFontMetrics()會返回一個FontMetrics對象,調用前記得先設置字體大小,該對象有5個屬性,分別是:top,ascent,descent,bottom,leading(行間距).注意前2個的值爲負。