天天看點

自定義控件那些事兒 ----- 五【繪制文字】

一、文字繪制的基礎知識

還記得小時候學習寫字的時候,老使用四線格。當初就是了解說有一個區域,上下兩根線确定了整個書寫範圍,而第三根線就像是排排坐的人,所有的重心都在這個上面。如今,用到繪制文字的時候,需要對文字繪制有一個全新的認識。上下兩根确定了範圍,沒錯!那個辨別“重心”的線也就是基線!

自定義控件那些事兒 ----- 五【繪制文字】

對于這個詳細的解讀,大神已經做了很好的描述。

自定義控件那些事兒 ----- 五【繪制文字】

這也就有了我們所需要的五基線!

借此,也正好記憶清楚,各個關鍵計算的關系:

//        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

表示在路徑上的水準偏移和縱向偏移。目前展示效果中,位于内圈的是沒有設定偏移量的效果。這是偏移量後,“天”離基線位置遠了,整體離中心點遠了!

以上就是文本繪制的全部内容了。。。。。

源碼傳送門

如今我終于明白,我渡得過萬裡狂風,渡得過千條性命,渡得過詩酒年華,卻渡不過,你不顧而去的目光。

天生微涼的手心,少了你的溫度,如何是好。

繼續閱讀