2010-09-06 59 views
90

任何直接測量文字高度的方法? 我現在的做法是使用Paint的measureText()來獲取寬度,然後通過反覆試驗找到一個值來獲得大致的高度。我也一直在搞FontMetrics,但所有這些看起來像吸吮近似的方法。測量畫布上的文字高度(Android)

我想要爲不同的分辨率縮放東西。我可以做到這一點,但我最終得到了具有大量計算以確定相對大小的令人難以置信的詳細代碼。我討厭它!一定有更好的方法。

回答

117

paint.getTextBounds()(對象的方法)

+1

這將產生非常奇怪的結果,當我評價文本的高度。短文本的結果高度爲12,而真正的長文本導致高度爲16(給定的字體大小爲16)。對我沒有意義(android 2.3.3) – AgentKnopf 2012-02-20 16:07:03

+34

高度的變化是你在文本中有下行的地方,即'高'比'低'高,因爲g下面的g部分是 – FrinkTheBrave 2012-11-08 13:32:15

1

您必須使用哪種Rect.width()Rect.Height()getTextBounds()返回來代替。這對我行得通。

+2

如果您要處理多個文本片段,則不是。原因在於我上面的答案。 – 2012-09-12 12:55:30

74

@ bramp的答案是正確的 - 部分,因爲它沒有提到的是,計算的邊界將是完全包含文本以0隱起點座標最小矩形,0

這意味着,例如「Py」的高度將不同於「py」或「hi」或「oi」或「aw」的高度,因爲按像素來說它們需要不同的高度。

這絕不等於經典java中的FontMetrics。

雖然文字的寬度並不是很痛苦,但身高是。

特別是,如果您需要垂直居中對齊繪製的文本,請嘗試獲取文本「a」(不帶引號)的邊界,而不是使用您打算繪製的文本。 對我的作品......

這裏就是我的意思是:

Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG); 

paint.setStyle(Paint.Style.FILL); 
paint.setColor(color); 
paint.setTextAlign(Paint.Align.CENTER); 
paint.setTextSize(textSize); 

Rect bounds = new Rect(); 
paint.getTextBounds("a", 0, 1, bounds); 

buffer.drawText(this.myText, canvasWidth >> 1, (canvasHeight + bounds.height()) >> 1, paint); 
// remember x >> 1 is equivalent to x/2, but works much much faster 

垂直定心文本垂直意味着中心對齊邊框 - 這是不同的文本(帽,長信等)不同。但是我們實際上想要做的就是對齊渲染文本的基線,使它們不會出現高架或凹槽。所以,只要我們知道最小字母的中心(例如「a」),我們就可以重新使用它的對齊方式來處理其餘的文本。這將中心對齊所有文本以及基線對齊它們。

+18

多年沒見過'x >> 1'。僅適用於:) – keaukraine 2012-12-13 13:00:43

+50

考慮到克里斯的評論,一個好的現代編譯器將會看到'x/2'並將其優化爲'x >> 1' – 2013-03-15 00:59:57

+31

@keaukraine'x/2'在閱讀代碼時更加友好。 – d3dave 2013-08-07 20:51:22

2

您可以使用getTextSize()方法簡單地獲取Paint對象的文本大小。 例如:

Paint mTextPaint = new Paint (Paint.ANTI_ALIAS_FLAG); 
//use densityMultiplier to take into account different pixel densities 
final float densityMultiplier = getContext().getResources() 
      .getDisplayMetrics().density; 
mTextPaint.setTextSize(24.0f*densityMultiplier); 

//... 

float size = mTextPaint.getTextSize(); 
+0

'24.0f'從哪裏來? – Erigami 2015-02-17 02:29:14

+0

24.0f這僅僅是一個文本大小爲 – moondroid 2015-02-17 09:25:23

2

您可以使用android.text.StaticLayout類指定所需的範圍,然後調用getHeight()。您可以通過調用其draw(Canvas)方法來繪製文本(包含在佈局中)。

0

如果有人仍然有問題,這是我的代碼。

我有一個自定義視圖,它是正方形(寬度=高度),我想給它分配一個字符。 onDraw()顯示如何獲得角色的高度,雖然我沒有使用它。角色將顯示在視圖的中間。

public class SideBarPointer extends View { 

    private static final String TAG = "SideBarPointer"; 

    private Context context; 
    private String label = ""; 
    private int width; 
    private int height; 

    public SideBarPointer(Context context) { 
     super(context); 
     this.context = context; 
     init(); 
    } 

    public SideBarPointer(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     this.context = context; 
     init(); 
    } 

    public SideBarPointer(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
     this.context = context; 
     init(); 
    } 

    private void init() { 
//  setBackgroundColor(0x64FF0000); 
    } 

    @Override 
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){ 
     super.onMeasure(widthMeasureSpec, heightMeasureSpec); 

     height = this.getMeasuredHeight(); 
     width = this.getMeasuredWidth(); 

     setMeasuredDimension(width, width); 
    } 

    protected void onDraw(Canvas canvas) { 
     float mDensity = context.getResources().getDisplayMetrics().density; 
     float mScaledDensity = context.getResources().getDisplayMetrics().scaledDensity; 

     Paint previewPaint = new Paint(); 
     previewPaint.setColor(0x0C2727); 
     previewPaint.setAlpha(200); 
     previewPaint.setAntiAlias(true); 

     Paint previewTextPaint = new Paint(); 
     previewTextPaint.setColor(Color.WHITE); 
     previewTextPaint.setAntiAlias(true); 
     previewTextPaint.setTextSize(90 * mScaledDensity); 
     previewTextPaint.setShadowLayer(5, 1, 2, Color.argb(255, 87, 87, 87)); 

     float previewTextWidth = previewTextPaint.measureText(label); 
//  float previewTextHeight = previewTextPaint.descent() - previewTextPaint.ascent(); 
     RectF previewRect = new RectF(0, 0, width, width); 

     canvas.drawRoundRect(previewRect, 5 * mDensity, 5 * mDensity, previewPaint); 
     canvas.drawText(label, (width - previewTextWidth)/2, previewRect.top - previewTextPaint.ascent(), previewTextPaint); 

     super.onDraw(canvas); 
    } 

    public void setLabel(String label) { 
     this.label = label; 
     Log.e(TAG, "Label: " + label); 

     this.invalidate(); 
    } 
} 
+2

-1的示例,用於onDraw()中的分配:如果您要在類中聲明這些字段(在構造函數中啓動)並在其中重新使用它,它將產生大量的性能優勢onDraw有()。 – zoltish 2015-10-31 07:45:45

+0

@zoltish感謝bro的評論,但倒票?!通常用於重複/錯誤的答案,而不是相對的甚至是信息量的答案。無論如何你是對的,對於那些正在使用我的建議的人來說是正確的。 – Hesam 2015-11-01 20:05:35

13

高度是您在Paint變量上設置的文本大小。

另一種方法來找出高度

mPaint.getTextSize(); 
67

有測量取決於你所需要的高度不同的方式。

getTextBounds

如果你正在做的事情一樣精確定心固定文本少量,你可能想getTextBounds。你可以得到邊框這樣

Rect bounds = new Rect(); 
mTextPaint.getTextBounds(mText, 0, mText.length(), bounds); 
int height = bounds.height(); 

正如你可以看到下面的圖片,不同的字符串會給出不同的高度上(顯示爲紅色)。

enter image description here

這些不同的高度可能是在某些情況下處於劣勢的時候,你只需要一個恆定的高度,無論文本是什麼。請參閱下一節。

Paint.FontMetrics

您可以從字體規格計算字體的HIGHT。高度始終相同,因爲它是從字體獲得的,而不是任何特定的文本字符串。

Paint.FontMetrics fm = mTextPaint.getFontMetrics(); 
float height = fm.descent - fm.ascent; 

基線是文本所在的行。一般來說,下降通常是角色在線下方最遠,而上升通常是角色越過線上最遠的角色。爲了獲得高度,你必須減去上升,因爲它是一個負值。 (基線是y=0y會降低屏幕。)

看下面的圖像。這兩個字符串的高度爲234.375

enter image description here

如果你想要的行高度,而不僅僅是文字高度,你可以做到以下幾點:

float height = fm.bottom - fm.top + fm.leading; // 265.4297 

這些都是bottom而行top。前導(行間距)通常爲零,但您應該添加它。

以上圖片來自this project。你可以玩弄它看看Font Metrics是如何工作的。

StaticLayout

用於測量多行文本的高度,你應該使用StaticLayout。我談論它在一些細節中this answer,但基本的方式來獲得這個高度是這樣的:

String text = "This is some text. This is some text. This is some text. This is some text. This is some text. This is some text."; 

TextPaint myTextPaint = new TextPaint(); 
myTextPaint.setAntiAlias(true); 
myTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density); 
myTextPaint.setColor(0xFF000000); 

int width = 200; 
Layout.Alignment alignment = Layout.Alignment.ALIGN_NORMAL; 
float spacingMultiplier = 1; 
float spacingAddition = 0; 
boolean includePadding = false; 

StaticLayout myStaticLayout = new StaticLayout(text, myTextPaint, width, alignment, spacingMultiplier, spacingAddition, includePadding); 

float height = myStaticLayout.getHeight(); 
+0

很好的解釋。截圖來自哪些應用? – 2017-02-22 20:22:46

+1

@MichealJohnson,我將該應用程序添加爲[GitHub項目](https://github.com/suragch/AndroidFontMetrics)。 – Suragch 2017-03-03 00:15:06