Нарисуйте подходящий текст в указанном прямоугольнике - PullRequest
4 голосов
/ 05 января 2011

Используя холст, я хочу нарисовать некоторый короткий текст метки (1-2 символа), который помещается в некоторый указанный прямоугольник.По ряду других причин используемое мной масштабирование таково, что размеры этого прямоугольника малы, т. Е. Около 1.

Проблема, с которой я сталкиваюсь, заключается в том, чтобы вычислить оптимальное (как можно большее, чтобы текствсе еще соответствует) размеру текста, используемому с Paint.setTextSize до рисования текста (что я делаю, используя Canva.drawText()).Для этого я могу либо использовать объект Paint.Fontmetrics, чтобы получить некоторые общие размеры шрифта в виде чисел с плавающей запятой, либо getTextBounds(String text, int start, int end, Rect bounds), чтобы получить ограничивающую рамку текста в виде целочисленного прямоугольника.Из-за масштабирования, которое я использую, целочисленная ограничивающая рамка из последнего является неточной для вычисления оптимального размера текста для моей цели.

Мне нужен какой-то метод, чтобы получить ограничивающую рамку текста с более высокимточность (например, getStringBounds(String str, Graphics context) in java.awt.FontMetrics), но я не нашел подходящего метода.

Ответы [ 2 ]

7 голосов
/ 26 мая 2013

Я теперь тоже был занят этой проблемой.

К сожалению, мне пока не удалось установить собственный источник, но я почти уверен, что текстовые измерения (как getTextBounds () и measureText ())сильно отличаются от реального вывода текста, особенно для шрифтов небольшого размера (как видно на скриншоте Морица ).Я предполагаю, что методы измерения используют ширину с плавающей точкой для символа, а реальный текстовый вывод использует int (предположительно из-за производительности).Это, конечно, потерпит неудачу, если вам нужен абсолютно точный размер (например, для автоматического изменения размера).Я немного поэкспериментировал с моноширинным шрифтом.Это изображение показывает некоторые из этих экспериментов:

Android Autoscale experiments.

Масштаб текста в этих экспериментах был установлен путем автоматического масштабирования.

В верхнем ряду я создал блоки с целочисленным приращением.Они соответствуют выводу текста Android.Видите ли, последний шифр не соответствует экрану!

Во 2-й строке ящики были созданы с приращением с плавающей точкой.Боксы лучше соответствуют экрану, но не соответствуют выводу текста на Android!

В последней строке поля были увеличены на величину с плавающей запятой, и текст выводился символ за символом с тем же шагом.И поля, и символы подходят идеально.

В моем заключении, в настоящее время невозможно установить вывод текста на Android с точной шириной.Кажется, проблема не в методах измерения, которые достаточно точны.Кажется, проблема в том, что вы не можете установить точную ширину текста с помощью setTextSize ().

Попробуйте воспроизвести следующее:

    float width = 100; // define a width which should be achieved
    m_textPaint.setTextSize( 100 ); // set a text size surely big enough
    Rect r = new Rect();
    String s = new String("This is a test text");
    m_textPaint.getTextBounds( s, 0, s.length(), r ); // measure the text with a random size
    float fac = width / r.width(); // compute the factor, which will scale the text to our target width
    Log.i( "MyTestOutput", "current text width:" + r.width() );
    Log.i( "MyTestOutput", "wanted text width:" + width );
    Log.i( "MyTestOutput", "factor:" + fac );
    Log.i( "MyTestOutput", "expected result:" + (float) r.width() * fac );
    m_textPaint.setTextSize( m_textPaint.getTextSize() * fac );
    m_textPaint.getTextBounds( s, 0, s.length(), r ); // now final measurement: whats the real width?
    Log.i( "MyTestOutput", "real result:" + r.width() );

Я получаю вывод:

05-26 12: 18: 18.420: I / MyTestOutput (23607): текущая ширина текста: 1125

05-26 12: 18: 18.425: I / MyTestOutput (23607):ширина полезного текста: 100,0

05-26 12: 18: 18,425: I / MyTestOutput (23607): коэффициент: 0,08888889

05-26 12: 18: 18,425: I / MyTestOutput (23607): ожидаемый результат: 100.0

05-26 12: 18: 18.430: I / MyTestOutput (23607): реальный результат: 94

Так что, на мой взгляд, единственный способдобиться очень точного автоматически масштабируемого текста, а) а) автоматически масштабировать его, измеряя и задавая размер текста б) выводить его символ за символом с помощью собственного вычисленного приращения.

К сожалению, это работает только для моноширинных шрифтов.Для других шрифтов это будет сложнее, но также возможно.

1 голос
/ 05 января 2011

Я сделал это всего несколько дней назад: Смотрите мой блог .

Вы бы использовали StaticLayout :

// bmp1 is a source bitmap (in that case 44x44px big).
// density is the screen density, you will need to retrieve it yourself as well.

canvas.drawBitmap(BitmapFactory.decodeResource(context.getResources(), R.drawable.overlay_44x44), new Matrix(), null);

// Initialize using a simple Paint object.
final TextPaint tp = new TextPaint(WHITE);

// Save the canvas state, it might be re-used later.
canvas.save();

// Create a padding to the left & top.
canvas.translate(4*density, 4*density);

// Clip the bitmap now.
canvas.clipRect(new Rect(0, 0, bmp1.getWidth(),(int) (bmp1.getHeight() - (6*density))));

// Basic StaticLayout with mostly default values
StaticLayout sl = new StaticLayout(message, tp, bmp1.getWidth(), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
sl.draw(canvas);

// Restore canvas.
canvas.restore();
...