Как надежно определить ширину многострочной строки?
Я пытаюсь вычислить ширину многострочного абзаца текста. Насколько я знаю, единственным классом, который может это сделать в Android, является класс StaticLayout (или DynamicLayout). При использовании этого класса я не получаю надлежащую длину моего фрагмента текста, но измеренные размеры иногда меньше и иногда больше в зависимости от размера текста.
Итак, я в основном ищу способ надежного измерения ширины многострочной текстовой строки.
На следующем рисунке показано, как измеренная ширина расходится с фактической длиной текста в разных размерах текста. ![Diverging text and measure]()
Создается скриншот, запускающий следующий код в пользовательском представлении:
@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 );
}
}
Ответы
Ответ 1
Вы можете попробовать использовать текстовые ограничения.
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());
}
Ответ 2
У меня была аналогичная проблема, когда измеренная ширина текста была немного разряжена, как только вы установите Typeface на краску, это исчезнет.
Поэтому, прежде чем использовать объект paint
в StaticLayout
, просто установите Typeface:
textPaint.setTypeface(Typeface.create("sans-serif", Typeface.NORMAL))
или любой другой шрифт, который вы хотите.
Ответ 3
Здесь вы можете получить многострочную ширину любой длины текста. usableButtonWidth
может быть заданным текстовым пространством. Я использовал usableButtonWidth
= width кнопки - padding. Но можно использовать любое значение по умолчанию.
Используя StaticLayout, вы можете получить высоту текста для usableButtonWidth
. Затем я просто пытаюсь уменьшить доступную ширину, уменьшив ее на 1px в цикле. Если высота увеличивается, мы узнаем, что максимально допустимая ширина была максимально допустимой.
Возвращает это значение как ширину многострочного текста.
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;
}
}