一、文字繪制的基礎知識
還記得小時候學習寫字的時候,老使用四線格。當初就是了解說有一個區域,上下兩根線确定了整個書寫範圍,而第三根線就像是排排坐的人,所有的重心都在這個上面。如今,用到繪制文字的時候,需要對文字繪制有一個全新的認識。上下兩根确定了範圍,沒錯!那個辨別“重心”的線也就是基線!
對于這個詳細的解讀,大神已經做了很好的描述。
這也就有了我們所需要的五基線!
借此,也正好記憶清楚,各個關鍵計算的關系:
// ascent = ascent線的y坐标 - baseline線的y坐标;
// descent = descent線的y坐标 - baseline線的y坐标;
// top = top線的y坐标 - baseline線的y坐标;
// bottom = bottom線的y坐标 - baseline線的y坐标;
并為在之後的應用Paint.FontMetrics計算出來各個基線的位置奠定基礎。
1,自定義控件,繪制文字
public class TextDrawView extends View {
/**
* 寫字筆
*/
private Paint textPaint;
public TextDrawView(Context context) {
super(context);
}
public TextDrawView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public TextDrawView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int baseLineX = MainApplication.getApplication().getWidth() / 4;//内容繪制在偏中間,便于觀察
int baseLineY = 200;
//畫基線
textPaint = new Paint();
textPaint.setColor(getResources().getColor(R.color.chocolate));
// canvas.drawLine(baseLineX, baseLineY, 3000, baseLineY, textPaint);
canvas.drawLine(0, baseLineY, 3000, baseLineY, textPaint);
textPaint.setColor(getResources().getColor(R.color.chocolate));
canvas.drawLine(baseLineX, 0, baseLineX, 2000, textPaint);
//寫文字
textPaint.setColor(Color.GREEN);
textPaint.setTextSize(160); //以px為機關
textPaint.setTextAlign(Paint.Align.LEFT);
canvas.drawText("HelloWorld!You're Special,good good study", baseLineX, baseLineY, textPaint);
}
}
2,使用自定義控件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.future.drawtextdemo.MainActivity">
<com.future.drawtextdemo.view.TextDrawView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
其他則是建立預設項目即可!
3,添加量屏工具
public class MainApplication extends Application {
private static MainApplication application;
// 螢幕的寬高
private int width = 0;
private int height = 0;
public static MainApplication getApplication() {
return application;
}
@Override
public void onCreate() {
super.onCreate();
application = this;
}
public int getWidth() {
if (width == 0) {
// 擷取螢幕的寬高
WindowManager wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
width = wm.getDefaultDisplay().getWidth();// 螢幕寬度
height = wm.getDefaultDisplay().getHeight();// 螢幕高度
}
return width;
}
public int getHeight() {
if (height == 0) {
WindowManager wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
width = wm.getDefaultDisplay().getWidth();// 螢幕寬度
height = wm.getDefaultDisplay().getHeight();// 螢幕高度
}
return height;
}
}
記得在清單檔案中添加Application。
4,展示效果
以兩線交點為基準點。目前設定setTextAlign()為LEFT。已下分别是設定Right、Center的效果。
二、文字繪制:五基線及常用屬性設定
依據前言介紹FontMetrics計算文字繪制五基線,在onDraw()中添加:
//繪制四條線
// ascent = ascent線的y坐标 - baseline線的y坐标;
// descent = descent線的y坐标 - baseline線的y坐标;
// top = top線的y坐标 - baseline線的y坐标;
// bottom = bottom線的y坐标 - baseline線的y坐标;
Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
int ascentY = (int) fontMetrics.ascent + baseLineY;
int descentY = (int) fontMetrics.descent + baseLineY;
int topY = (int) fontMetrics.top + baseLineY;
int bottomY = (int) fontMetrics.bottom + baseLineY;
textPaint.setTextSize(40);
textPaint.setColor(getResources().getColor(R.color.cyan));
canvas.drawLine(0, ascentY, 3000, ascentY, textPaint);
canvas.drawText("ascent", baseLineX - 300, ascentY, textPaint);
textPaint.setColor(getResources().getColor(R.color.red));
canvas.drawLine(0, descentY, 3000, descentY, textPaint);
canvas.drawText("descent", baseLineX - 200, descentY, textPaint);
textPaint.setColor(getResources().getColor(R.color.black));
canvas.drawLine(0, topY, 3000, topY, textPaint);
canvas.drawText("top", baseLineX - 100, topY, textPaint);
textPaint.setColor(getResources().getColor(R.color.mediumvioletred));
canvas.drawLine(0, bottomY, 3000, bottomY, textPaint);
canvas.drawText("bottom", baseLineX + 100, bottomY, textPaint);
展示效果:
線條比較密集,設定文字大小更大,展示效果:
三、文字繪制最小區域及按照路徑繪制
經過以上的努力,能夠正常繪制文字。整個文字占用區域也是相對會有用的。在控制自定義控件中,需要量測文字占用區域。FontMetrics的擷取幫助下,能夠擷取文字占用區域的整體高度。通過paint.measureText(content)的方式可以量測文字占用寬度。基于此,可以繪制出目前文案占用的最小區域和最大區域。
public class TextDraw1View extends View {
/**
* 寫字筆
*/
private Paint textPaint;
public TextDraw1View(Context context) {
super(context);
}
public TextDraw1View(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public TextDraw1View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
String content = "good study";
int baseLineX = MainApplication.getApplication().getWidth() / 4;//内容繪制在偏中間,便于觀察
int baseLineY = 200;
//畫基線
textPaint = new Paint();
textPaint.setColor(getResources().getColor(R.color.chocolate));
// canvas.drawLine(baseLineX, baseLineY, 3000, baseLineY, textPaint);
canvas.drawLine(0, baseLineY, 3000, baseLineY, textPaint);
textPaint.setColor(getResources().getColor(R.color.chocolate));
canvas.drawLine(baseLineX, 0, baseLineX, 2000, textPaint);
textPaint.setTextSize(160); //以px為機關
//繪制占據大小區域
Paint.FontMetricsInt fontMetricsInt = textPaint.getFontMetricsInt();
int top = fontMetricsInt.top + baseLineY;
int bottom = fontMetricsInt.bottom + baseLineY;
int width = (int) textPaint.measureText(content);
Rect textRec = new Rect(baseLineX, top, baseLineX + width, bottom);
textPaint.setColor(getResources().getColor(R.color.chartreuse));
canvas.drawRect(textRec, textPaint);
//繪制文字最小矩形
int asent = fontMetricsInt.ascent + baseLineY;
int desent = fontMetricsInt.descent + baseLineY;
Rect minRec = new Rect(baseLineX, asent, baseLineX + width, desent);
textPaint.setColor(getResources().getColor(R.color.cyan));
canvas.drawRect(minRec, textPaint);
//寫文字
textPaint.setColor(Color.GREEN);
textPaint.setTextAlign(Paint.Align.LEFT);
canvas.drawText(content, baseLineX, baseLineY, textPaint);
}
}
展示效果:
文本繪制也可以依據路徑來繪制,示例如下:onDraw()中添加以下代碼:
//沿路徑書寫文字
textPaint.setTextSize(60); //以px為機關
textPaint.setColor(Color.DKGRAY);
textPaint.setAlpha(50);
textPaint.setStyle(Paint.Style.STROKE);
Path path = new Path();
path.addCircle(baseLineX, baseLineY, 100, Path.Direction.CCW);
canvas.drawPath(path, textPaint);
canvas.drawTextOnPath("天下武功,唯快不破!", path, 50, 40, textPaint);
canvas.drawTextOnPath("天下武功,唯快不破!", path, 0, 0, textPaint);
【為了展示效果較好,将之前的文案繪制和大小區域繪制注釋掉】
展示效果:
将同樣的内容繪制了兩遍,因為設定參數的不同,他們并沒有重合。
(1)path的設定是有方向的
目前設定路徑為圓形,Path.Direction.CCW為逆時針,Path.Direction.CW為順時針。很明顯,目前path方向為逆時針。
(2)hoffset和voffset
表示在路徑上的水準偏移和縱向偏移。目前展示效果中,位于内圈的是沒有設定偏移量的效果。這是偏移量後,“天”離基線位置遠了,整體離中心點遠了!
以上就是文本繪制的全部内容了。。。。。
源碼傳送門
如今我終于明白,我渡得過萬裡狂風,渡得過千條性命,渡得過詩酒年華,卻渡不過,你不顧而去的目光。
天生微涼的手心,少了你的溫度,如何是好。