• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • 自定義View學習3:canvas繪制文字

    標簽: android  canvas  自定義view  view  繪制  

    1canvas繪制文字的方式

    canvas的文字繪制方式有三種:drawText(),drawTextRun(),drawTextOnPath()。

    drawText(String text,float x,float y,Paint paint)
    

    drawText()是canvas 最基本的繪制方法:給出文字的內容和位置,Canvas按照要求去繪制文字,text是文字內容,x和y是文字的坐標,需要注意的是這個坐標并不是文字的左上角,而是一個與左下角比較接近的位置

    drawTexRun()
    

    drawTextRun() 是在 API 23 新加入的方法。它和 drawText() 一樣都是繪制文字,但加入了兩項額外的設置——上下文和文字方向——用于輔助一些文字結構比較特殊的語言的繪制。

    drawTextonPath(String text,Path path,float hOffset,float vOffset,Paint paint);
    

    沿著一條path路徑來繪制文字。這個方法可以用來繪制豎向文字,斜向文字等等參數:hOffset 和 vOffset。它們是文字相對于 Path 的水平偏移量和豎直偏移量,利用它們可以調整文字的位置。例如你設置 hOffset 為 5, vOffset 為 10,文字就會右移 5 像素和下移 10 像素。

    2.StaticLayout
    staticLayouty也是一個使用canvas來繪制文字,不過它并不使用canvas的繪制方法。canvas.drawText只能繪制單行的文字,而且不能換行。
    * 到了view的邊緣,文字繼續向后繪制到看不到的地方為不能自動換行
    * 不能在換行符\n處換行
    所以使用canvas.drawtext繪制文字,需要自己把文字切斷后,分多次使用drawText()來繪制。
    staticLayout并不是view或者viewGroup,而是android.text.Layout的自雷,他是純粹用來繪制文字的,StaticLayout支持換行,它既支持可以為文字設置寬度上限來讓文字自動換行,也會在\n出主動換行。

    StaticLayout(CharSequence source, TextPaint paint, int width, Layout.Alignment align, float spacingmult, float spacingadd, boolean includepad)
    
    • width 是文字區域的寬度,文字到達這個寬度后就會自動換行;
    • align 是文字的對齊方向;
    • spacingmult 是行間距的倍數,通常情況下填 1 就好;
    • spacingadd 是行間距的額外增加值,通常情況下填 0 就好;
    • includeadd 是指是否在文字上下添加額外的空間,來避免某些過高的字符的繪制出現越界。
      如果需要進行多行文字的繪制,并且對文字的排列和樣式沒有太復雜的要求,使用staticLayout就可以。

    Paint對于文字繪制的輔助
    Paint 對文字繪制的輔助,有兩類方法:設置顯示效果的和測量文字尺寸的。

    1.設置顯示效果

    • setTextSize(float size);//設置text的大小
    • setTypeface(Typeface typeface)//設置字體的樣式設置不同的 Typeface 就可以顯示不同的字體。我們中國人談到「字體」,比較熟悉的詞是 font, typeface 和 font 是一個意思,都表示字體。 Typeface 這個類的具體用法,需要了解的話可以直接看文檔,很簡單。
    • setFakeBlodText(boolean fakeBoldText)//設置偽粗體,之所以叫偽粗體,是因為程序并不是通過weight設置的粗體,而是在程序運行時把文字給描粗了。
    • setStrikeThruText(boolean strikeThruText)//設置刪除線
    • setUnderlineText(boolean underlineText)//設置下劃線
    • setTextSkewX(float skewX)//設置文字的傾斜角度
    • setTextScaleX(float scaleX)//設置文字的橫向縮放,也就是文字變胖變瘦
    • setLetterSpacing(float letterSpacing) //設置字符間距,默認是0

    2.測試文字尺寸

    不論是文字,還是圖形或 Bitmap,只有知道了尺寸,才能更好地確定應該擺放的位置。由于文字的繪制和圖形或 Bitmap 的繪制比起來,尺寸的計算復雜得多,所以它有一整套的方法來計算文字尺寸。

    float getFontSpacing() 
    

    獲取推薦的行間距。即推薦的兩行文字的 baseline 的距離。這個值是系統根據文字的字體和字號自動計算的。它的作用是當你要手動繪制多行文字(而不是使用 StaticLayout)的時候,可以在換行的時候給 y 坐標加上這個值來下移文字。

       canvas.drawText(texts[0], 100, 150, paint);
       canvas.drawText(texts[1], 100, 150 + paint.getFontSpacing, paint);
       canvas.drawText(texts[2], 100, 150 + paint.getFontSpacing * 2, paint);
    
    FontMetircs getFontMetrics()
    

    獲取paint的fontMetircs。FontMetrics 是個相對專業的工具類,它提供了幾個文字排印方面的數值:ascent, descent, top, bottom, leading。

    這里寫圖片描述
    如圖,圖中有兩行文字,每一行都有 5 條線:top, ascent, baseline, descent, bottom。(leading 并沒有畫出來,因為畫不出來,下面會給出解釋)

    • baseline: 上圖中黑色的線。前面已經講過了,它的作用是作為文字顯示的基準線。

    • ascent / descent: 上圖中綠色和橙色的線,它們的作用是限制普通字符的頂部和底部范圍。
      普通的字符,上不會高過 ascent ,下不會低過 descent ,例如上圖中大部分的字形都顯示在 ascent 和 descent 兩條線的范圍內。具體到 Android 的繪制中, ascent 的值是圖中綠線和 baseline 的相對位移,它的值為負(因為它在 baseline 的上方); descent 的值是圖中橙線和 baseline 相對位移,值為正(因為它在 baseline 的下方)。

    • top / bottom: 上圖中藍色和紅色的線,它們的作用是限制所有字形( glyph )的頂部和底部范圍。
      除了普通字符,有些字形的顯示范圍是會超過 ascent 和 descent 的,而 top 和 bottom 則限制的是所有字形的顯示范圍,包括這些特殊字形。例如上圖的第二行文字里,就有兩個泰文的字形分別超過了 ascent 和 descent 的限制,但它們都在 top 和 bottom 兩條線的范圍內。具體到 Android 的繪制中, top 的值是圖中藍線和 baseline的相對位移,它的值為負(因為它在 baseline 的上方);

    • bottom 的值是圖中紅線和 baseline 相對位移,值為正(因為它在 baseline 的下方)。

    • leading: 這個詞在上圖中沒有標記出來,因為它并不是指的某條線和 baseline 的相對位移。 leading 指的是行的額外間距,即對于上下相鄰的兩行,上行的 bottom 線和下行的 top 線的距離,也就是上圖中第一行的紅線和第二行的藍線的距離(對,就是那個小細縫)。
    • leading 這個詞的本意其實并不是行的額外間距,而是行距,即兩個相鄰行的 baseline之間的距離。不過對于很多非專業領域,leading 的意思被改變了,被大家當做行的額外間距來用;而 Android 里的 leading ,同樣也是行的額外間距的意思。
      另外,leading 在這里應該讀作 “ledding” 而不是 “leeding” 哦。原因就不說了,我這越扯越遠沒邊了。
      FontMetrics 提供的就是 Paint 根據當前字體和字號,得出的這些值的推薦值。它把這些值以變量的形式存儲,供開發者需要時使用。

      • FontMetrics.ascent:float 類型。
      • FontMetrics.descent:float 類型。
      • FontMetrics.top:float 類型。
      • FontMetrics.bottom:float 類型。
      • FontMetrics.leading:float 類型。
        另外,ascent 和 descent 這兩個值還可以通過 Paint.ascent() 和 Paint.descent() 來快捷獲取。
        FontMetrics 和 getFontSpacing():
        從定義可以看出,上圖中兩行文字的 font spacing (即相鄰兩行的 baseline 的距離) 可以通過 bottom - top + leading (top 的值為負,前面剛說過,記得吧?)來計算得出。
        但你真的運行一下會發現, bottom - top + leading 的結果是要大于 getFontSpacing() 的返回值的。
        兩個方法計算得出的 font spacing 竟然不一樣?
        這并不是 bug,而是因為 getFontSpacing() 的結果并不是通過 FontMetrics 的標準值計算出來的,而是另外計算出來的一個值,它能夠做到在兩行文字不顯得擁擠的前提下縮短行距,以此來得到更好的顯示效果。所以如果你要對文字手動換行繪制,多數時候應該選取 getFontSpacing() 來得到行距,不但使用更簡單,顯示效果也會更好。
        getFontMetrics() 的返回值是 FontMetrics 類型。它還有一個重載方法 getFontMetrics(FontMetrics fontMetrics) ,計算結果會直接填進傳入的 FontMetrics 對象,而不是重新創建一個對象。這種用法在需要頻繁獲取 FontMetrics 的時候性能會好些。
        另外,這兩個方法還有一對同樣結構的對應的方法 getFontMetricsInt() 和 getFontMetricsInt(FontMetricsInt fontMetrics) ,用于獲取 FontMetricsInt 類型的結果。
    • getTextBounds(String text, int start, int end, Rect bounds) //獲取文字的顯示范圍。參數里,text 是要測量的文字,start 和 end 分別是文字的起始和結束位置,bounds 是存儲文字顯示范圍的對象,方法在測算完成之后會把結果寫進 bounds。

      paint.setStyle(Paint.Style.FILL);
      canvas.drawText(text, offsetX, offsetY, paint);
      paint.getTextBounds(text, 0, text.length(), bounds);
      bounds.left += offsetX;
      bounds.top += offsetY;
      bounds.right += offsetX;
      bounds.bottom += offsetY;
      paint.setStyle(Paint.Style.STROKE);
      canvas.drawRect(bounds, paint);
      
    • float measureText(String text) //測量文字的寬度并返回。

      canvas.drawText(text, offsetX, offsetY, paint);
      float textWidth = paint.measureText(text);
      canvas.drawLine(offsetX, offsetY, offsetX + textWidth, offsetY, paint);
      

      如下圖:
      這里寫圖片描述

    咦,前面有了 getTextBounds(),這里怎么又有一個 measureText()?
    如果你用代碼分別使用 getTextBounds() 和 measureText() 來測量文字的寬度,你會發現 measureText() 測出來的寬度總是比 getTextBounds() 大一點點。這是因為這兩個方法其實測量的是兩個不一樣的東西。

    • getTextBounds: 它測量的是文字的顯示范圍(關鍵詞:顯示)。形象點來說,你這段文字外放置一個可變的矩形,然后把矩形盡可能地縮小,一直小到這個矩形恰好緊緊包裹住文字,那么這個矩形的范圍,就是這段文字的 bounds。

    • measureText(): 它測量的是文字繪制時所占用的寬度(關鍵詞:占用)。前面已經講過,一個文字在界面中,往往需要占用比他的實際顯示寬度更多一點的寬度,以此來讓文字和文字之間保留一些間距,不會顯得過于擁擠。上面的這幅圖,我并沒有設置 setLetterSpacing() ,這里的 letter spacing 是默認值 0,但你可以看到,圖中每兩個字母之間都是有空隙的。另外,下方那條用于表示文字寬度的橫線,在左邊超出了第一個字母 H 一段距離的,在右邊也超出了最后一個字母 r(雖然右邊這里用肉眼不太容易分辨),而就是兩邊的這兩個「超出」,導致了 measureText() 比 getTextBounds() 測量出的寬度要大一些。

    • 在實際的開發中,測量寬度要用 measureText() 還是 getTextBounds() ,需要根據情況而定。不過你只要掌握了上面我所說的它們的本質,在選擇的時候就不會為難和疑惑了。
    • getTextWidths(String text, float[] widths) // 獲取字符串中每個字符的寬度,并把結果填入參數 widths。這相當于 measureText() 的一個快捷方法,它的計算等價于對字符串中的每個字符分別調用 measureText() ,并把它們的計算結果分別填入 widths 的不同元素。
    • int breakText(String text, boolean measureForwards, float maxWidth, float[] measuredWidth)//這個方法也是用來測量文字寬度的。但和 measureText() 的區別是, breakText() 是在給出寬度上限的前提下測量文字的寬度。如果文字的寬度超出了上限,那么在臨近超限的位置截斷文字。
      學習來源:http://hencoder.com/ui-1-3/
    版權聲明:本文為ibelieveyouwxy原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/ibelieveyouwxy/article/details/80399320

    智能推薦

    Android自定義View學習四---Canvas畫布操作

    Canvas之畫布操作 內容來自:安卓自定義View進階-Canvas之畫布操作 基本操作 位移 translate是坐標系的移動,位移是基于當前位置移動,而不是每次基于屏幕左上角的(0,0)點移動 縮放(scale) 縮放提供了兩個方法,如下: 縮放的中心默認為坐標原點,而縮放中心軸就是坐標軸,第二個方法的px和py,用來控制縮放中心位置 使用第二種方法讓縮放中心位置稍微改變一下,如下: 當縮放...

    Android 自定義View----文字繪制(文字居中自動換行)

    c 使用canvas繪制文字非常簡單,但文字繪制根據baseLine無法劇中,網上說法很多,有點麻煩,這里用到一個非常簡單的辦法,先來看下文字的繪制參考線 圖片直接百度復制的,不是自己畫的,有時間自己畫一個; 文字上下居中其實很簡單 4多行繪制有兩種辦法:  先來看下StaticLayout StaticLayout很好用,系統的TextView里面也用到了,但是如果有自己的需求,隨意在...

    安卓自定義View進階-Canvas之圖片文字

    安卓自定義View進階-Canvas之圖片文字 參考文章: 轉載GcsSloop對內容進行添加和減少 wufenglong 上一篇Canvas之繪制基本圖形中我們了解了如何使用Canvas繪制基本圖形,本次了解一些基本的畫布操作。 一.Canvas的常用操作速查表 二.Canvas基本操作詳解 1.繪制圖片 (1)drawPicture 繪制有兩種方法,drawPicture(矢量圖) 和 dra...

    自定義View——Canvas 畫布

    前言 網上自定義View的文章已經很多了,但不是我的。。。 1.還是那句話,別人的東西,永遠在被人腦子里!哪怕看了很多遍,實踐很多次,沒有自己的總結,一段時間后,再拿起來還是很費力,又要重新尋找資源,效率太低。 2.自定義View,可以說是android UI的難點與核心。了解每個細節,熟練掌握自定義View,設計UI也就信手拈來。   于是,就開始了屬于自己的自定義View的系列。內容...

    Android自定義View(四) -- Canvas

    前面學習的內容: Android自定義View(一) – 初識 Android自定義View(二) – Paint詳解 Android自定義View(三) – drawText() 今天繼續學習Android自定義View第四篇內容Canvas。 本文計劃根據HenCoder系列文章進行學習,所以代碼風格及博文素材可能會摘自其中。 1 范圍裁切 范圍裁切有兩個方...

    猜你喜歡

    自定義 View - Canvas 詳解

    1.Canvas Canvas 是我們繪制各種圖形或文字時主要的操作對象,因為繪制繪制過程調用的都是它的 drawXX 方法。官方給出的 Canvas 的解釋: The Canvas class holds the “draw” calls. To draw something, you need 4 basic components: A Bitmap to hold t...

    Android 自定義View Canvas

    上一篇在android 自定義view Paint 里面 說了幾種常見的Point 屬性 繪制圖形的時候下面總有一個canvas ,Canvas 是是畫布 上面可以繪制點,線,正方形,圓,等等,需要和Paint 結合一起 使用,比如畫畫 需要畫筆和紙。 Canvas 常用的方法如下 (1) drawColor(@ColorInt int color) 繪制背景色 (2)drawRGB(int r,...

    HTML中常用操作關于:頁面跳轉,空格

    1.頁面跳轉 2.空格的代替符...

    freemarker + ItextRender 根據模板生成PDF文件

    1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...

    電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!

    Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...

    精品国产乱码久久久久久蜜桃不卡