Нарисуйте текст, подходящий к некоторому указанному прямоугольнику

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

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

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


person Christian Gawron    schedule 05.01.2011    source источник


Ответы (2)


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

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

Эксперименты по автомасштабированию Android.

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

В верхнем ряду я создал блоки с целым шагом. Они соответствуют текстовому выводу 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

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

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

person user2328447    schedule 26.05.2013

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

Вы должны использовать 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();
person Sebastian Roth    schedule 05.01.2011
comment
Извините, я вижу, что мой первоначальный вопрос был не очень точным. Проблема не в верстке текста (длиной текста всего 1-2 символа), а в том, чтобы рассчитать оптимальный размер текста. - person Christian Gawron; 05.01.2011