Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android學習16#--學習canvas.drawText

android學習16#--學習canvas.drawText

編輯:關於Android編程

本來這篇文章是要寫寫我在設計高級跑馬燈程序的心得的,但是編寫過程中花了近一天多的時間搞明白canvas.drawText中的第三個參數[float y]代表的真實含義。學習本文應該能幫助大家掌握FontMetrics類和Rect類成員變量值具體含義。

drawText引出問題

先來看看api中是如何定義drawText的參數。

    /**
     * Draw the text, with origin at (x,y), using the specified paint. The
     * origin is interpreted based on the Align setting in the paint.
     *
     * @param text  The text to be drawn
     * @param x     The x-coordinate of the origin of the text being drawn
     * @param y     The y-coordinate of the baseline of the text being drawn
     * @param paint The paint used for the text (e.g. color, size, style)
     */
    public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) {
        native_drawText(mNativeCanvasWrapper, text, 0, text.length(), x, y, paint.mBidiFlags,
                paint.getNativeInstance(), paint.mNativeTypeface);
    }

簡單解釋下各參數:
@param text:要顯示的文本內容,這個不難理解。
@param x:文本相對屏幕原點x方向距離,沒有更深的含義,也比較好理解
@param y:文本的baseline相對屏幕原點y方向距離。好,問題來了,baseline是個什麼鬼東東
@param paint:畫筆

baseline的來龍去脈

先看看baseline在文字區域的位置。通過一個實例來分析,這裡只貼主要的code。

    @Override
    protected void onDraw(Canvas canvas) {
        //super.onDraw(canvas);

        mRect = new Rect();
        mPaint = new Paint();
        mPaint.setTextSize(64);
        mPaint.setColor(Color.RED);

        Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt();
        mPaint.getTextBounds(textStr, 0, textStr.length(), mRect);

        int w = mRect.width();
        int h = mRect.height();

        mRect = new Rect(mRectLeft, mRectTop, mRectLeft+w, mRectTop+(-fontMetrics.top)+fontMetrics.bottom);

        canvas.drawRect(mRect, mPaint);

        mBaseLine = (mRect.bottom+mRect.top)/2
                - (fontMetrics.bottom+fontMetrics.top)/2;

        mBaseLine = -fontMetrics.top;

        /*其中y == mBaseLine的值*/
        mPaint.setColor(Color.WHITE);
        canvas.drawText(textStr, mRectLeft, mBaseLine, mPaint);

        mPaint.setColor(Color.BLUE);
        mPaint.setStrokeWidth(3);
        /*將mBaseLine所在的位置畫出來*/
        canvas.drawLine(mRectLeft, mBaseLine, mRectLeft+w, mBaseLine, mPaint);
    }

效果圖:
這裡寫圖片描述

分析

從上圖可以看出來,baseline並不是文字區域的底部,但是這根線的位置相信大家都熟悉,除非你沒有學過英語。

FontMetrics

FontMetrics是Paint靜態內部類,主要定義了Paint繪制文本時的關鍵坐標。API中這麼描述:

Class that describes the various metrics for a font at a given text size. Remember, Y values increase going down, so those values will be positive, and values that measure distances going up will be negative. This class is returned by getFontMetrics(). 

主要意思:根據設定的fontsize來獲得字體的各種變量值。通過getFontMetrics()方法來獲取。
FontMetrics類含有5個成員變量:

    public static class FontMetrics {
        /**
         * The maximum distance above the baseline for the tallest glyph in
         * the font at a given text size.
         */
        public float   top;
        /**
         * The recommended distance above the baseline for singled spaced text.
         */
        public float   ascent;
        /**
         * The recommended distance below the baseline for singled spaced text.
         */
        public float   descent;
        /**
         * The maximum distance below the baseline for the lowest glyph in
         * the font at a given text size.
         */
        public float   bottom;
        /**
         * The recommended additional space to add between lines of text.
         */
        public float   leading;
    }

很明顯所有的值都是基於baseline來算的。這裡我主要關注top這個值的定義。
top:api的注釋翻譯過來意思是字體可繪制區域最高位置與baseline的距離。但是它是個負數,所以-top就是我們的baseline坐標值。
ascent:字體下單個字符最高位置與baseline的距離
descent:字體下單個字符最低位置與baseline的距離,與ascent鏡像對應
bottom:字體可繪制區域最低位置與baseline的距離。
leading:字面翻譯是文本線額外的空間。一般都為0,不知道有何用處。

Rect

Rect類表示的一塊矩形區域。Paint類中getTextBounds()方法可以獲取對應font size下文本所占用矩形區域。記住這個矩形區域的坐標值也是相對baseline來計算的。
Rect類成員變量有4個,分別是left、top、right、bottom。由於文本的rect區域是相對baseline來計算的,因此真實的top跟bottom都要加上baseline的值。

借助一個實例來理解FontMetrics和Rect

主要源碼:

    @Override
    protected void onDraw(Canvas canvas) {
        //super.onDraw(canvas);

        mRect = new Rect();
        mPaint = new Paint();
        mPaint.getTextBounds(textStr, 0, 1, mRect);
        mPaint.setTextSize(textSize);
        mPaint.setColor(0xffF4A460);

        Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt();
        mPaint.getTextBounds(textStr, 0, textStr.length(), mRect);

        int w = mRect.width();
        int h = mRect.height();

        /*給fontMetrics區域填充0xffF4A460色*/
        mRect = new Rect(mRectLeft, mRectTop, mRectLeft+w, mRectTop+(-fontMetrics.top)+fontMetrics.bottom);
        canvas.drawRect(mRect, mPaint);

        /*計算baseline,其中mRectTop是控件頂部到父view的距離*/
        mBaseLine = -fontMetrics.top + mRectTop;

        /*其中y == mBaseLine的值*/
        mPaint.setColor(Color.WHITE);
        canvas.drawText(textStr, mRectLeft, mBaseLine, mPaint);

        mPaint.setColor(Color.BLUE);
        mPaint.setStrokeWidth(4);
        /*藍色線:將mBaseLine所在的位置畫出來*/
        canvas.drawLine(mRectLeft, mBaseLine, mRectLeft+w, mBaseLine, mPaint);

        mPaint.setColor(Color.GREEN);
        /*綠色線:將文字區域的bottom所在的位置畫出來*/
        canvas.drawLine(mRectLeft, mBaseLine+fontMetrics.bottom, mRectLeft+2*w
                , mBaseLine+fontMetrics.bottom, mPaint);

        mPaint.setColor(Color.RED);
        /*紅色線:將文字區域的top所在的位置畫出來*/
        canvas.drawLine(mRectLeft, mBaseLine+fontMetrics.top, mRectLeft+2*w
                , mBaseLine+fontMetrics.top, mPaint);

        mPaint.setColor(Color.GRAY);
        /*灰色線:將文字區域的ascent所在的位置畫出來*/
        canvas.drawLine(mRectLeft, mBaseLine+fontMetrics.ascent, mRectLeft+w+50
                , mBaseLine+fontMetrics.ascent, mPaint);

        mPaint.setColor(Color.WHITE);
        /*白色線:將文字區域的descent所在的位置畫出來*/
        canvas.drawLine(mRectLeft, mBaseLine+fontMetrics.descent, mRectLeft+w+50
                , mBaseLine+fontMetrics.descent, mPaint);

        mPaint.setColor(Color.YELLOW);
        /*黃色線:將文字區域的leading所在的位置畫出來*/
        canvas.drawLine(mRectLeft, mBaseLine+fontMetrics.leading, mRectLeft+w/2
                , mBaseLine+fontMetrics.leading, mPaint);

        /*將“測”字的rect用矩形繪出來*/
        mPaint.setColor(Color.BLACK);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.getTextBounds(textStr, 0, 1, mRect);
        mRect.top+=mBaseLine;
        mRect.bottom+=mBaseLine;
        canvas.drawRect(mRect, mPaint);

        /*將“測試:12hg”字的rect用矩形繪出來*/
        mPaint.setColor(Color.BLACK);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.getTextBounds(textStr, 0, 7, mRect);
        mRect.top+=mBaseLine;
        mRect.bottom+=mBaseLine;
        canvas.drawRect(mRect, mPaint);
    }

效果圖:

這裡寫圖片描述

FontMetrics:
1. 淺黃色區域就是文字的FontMetrics區域,可以看出來文字實在此區域垂直居中繪制
2. 紅色線:為FontMetrics的top
3. 灰色線:為FontMetrics的ascent
4. 黃色線:為FontMetrics的leading
5. 藍色線:為baseline線
6. 白色線:為FontMetrics的descent
7. 綠色線:為FontMetrics的bottom
Rect:
1. 第一個小黑矩形為“測”字的rect區域
2. 第二個長黑矩形為“測試:12hg”字的rect區域

總結

只要徹底弄明白baseline才能輕松掌握drawText接口,才不至於開發的時候總是搞不明白繪制的文字要麼偏上要麼偏下。

 
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved