I am trying to calculate the width of a multiline text paragraph. To my knowledge, the only class that can do this in Android is the StaticLayout (or DynamicLayout) class. When using this class i do no get the proper length of my text snippet but rather the measured the dimensions are sometimes smaller and sometimes greater depending on the text size.
So i am basically looking for a way to reliably measure the width of a multiline text string.
The following image shows how the measured width diverges from the actual text length in various text sizes.
The screenshot is created running the the following code in a custom View:
@Override
protected void onDraw( Canvas canvas ) {
for( int i = 0; i < 15; i++ ) {
int startSize = 10;
int curSize = i + startSize;
paint.setTextSize( curSize );
String text = i + startSize + " - " + TEXT_SNIPPET;
layout = new StaticLayout( text,
paint,
Integer.MAX_VALUE,
Alignment.ALIGN_NORMAL,
1.0f,
0.0f,
true );
float top = STEP_DISTANCE * i;
float measuredWidth = layout.getLineMax( 0 );
canvas.drawRect( 0, top, measuredWidth, top + curSize, bgPaint );
canvas.drawText( text, 0, STEP_DISTANCE * i + curSize, paint );
}
}
You could try using get text bounds.
private int calculateWidthFromFontSize(String testString, int currentSize)
{
Rect bounds = new Rect();
Paint paint = new Paint();
paint.setTextSize(currentSize);
paint.getTextBounds(testString, 0, testString.length(), bounds);
return (int) Math.ceil( bounds.width());
}
private int calculateHeightFromFontSize(String testString, int currentSize)
{
Rect bounds = new Rect();
Paint paint = new Paint();
paint.setTextSize(currentSize);
paint.getTextBounds(testString, 0, testString.length(), bounds);
return (int) Math.ceil( bounds.height());
}
I had a similar issue where the measured text width was off by a bit, once you set a Typeface to the paint this will go away.
So before you use the paint
object in the StaticLayout
just set the Typeface:
textPaint.setTypeface(Typeface.create("sans-serif", Typeface.NORMAL))
or whatever typeface you want.
Here's a way where you can get the multiline width of any text length. usableButtonWidth
can be a given text space. I used usableButtonWidth
= width of the button - padding. But any default value can be used.
Using StaticLayout, you can get the height of the text for the usableButtonWidth
. Then I just try to reduce the available width by decreasing it by 1px in a loop. If the height increases then we come to know that the previously used width was the maximum permissible.
Return this value as the width of multiline text.
private int getTextWidth(){
if(this.getText().length() != 0){
Paint textPaint = new Paint();
Rect bounds = new Rect();
textPaint.setTextSize(this.getTextSize());
if(mTypeface != null){
textPaint.setTypeface(mTypeface);
}
String buttonText = this.getText().toString();
textPaint.getTextBounds(buttonText, 0, buttonText.length(), bounds);
if(bounds.width() > usableButtonWidth){
TextPaint longTextPaint = new TextPaint();
longTextPaint.setTextSize(this.getTextSize());
if(mTypeface != null){
longTextPaint.setTypeface(mTypeface);
}
StaticLayout staticLayout = new StaticLayout(this.getText(), longTextPaint, usableButtonWidth,
Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
int textLineCount = (int)Math.ceil(staticLayout.getHeight() / bounds.height());
int multiLineTextWidth = usableButtonWidth;
while ((int)Math.ceil(staticLayout.getHeight() / bounds.height()) == textLineCount && multiLineTextWidth > 1){
multiLineTextWidth--;
staticLayout = new StaticLayout(this.getText(), longTextPaint, multiLineTextWidth,
Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
}
return multiLineTextWidth+1;
} else {
return bounds.width();
}
} else {
return 0;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With