Android paint text size

Полный список

— работаем с текстом

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

Определение размеров

Есть несколько методов, позволяющих определить размеры текста.

Для начала определим ширину всего текста и каждого символа по отдельности.

Project name: P1491_CanvasText
Build Target: Android 2.3.3
Application name: CanvasText
Package name: ru.startandroid.develop.p1491canvastext
Create Activity: MainActivity

В конструкторе DrawView мы создаем и настраиваем fontPaint, который будет использован для вывода текста. Здесь же мы вычисляем размеры текста. Метод measureText вернет ширину указанного текста. Сохраним ее в переменную width. А метод getTextWidths позволяет получить массив, содержащий значения ширины для каждого символа текста. Используем массив widths, размер которого равен кол-ву символов в тексте.

В onDraw рисуем текст. А под текстом рисуем линию шириной равной ранее полученной ширине текста — width, и используя массив widths выводим красные точки, отмечая ширину каждого символа.

Далее рассмотрим метод breakText. Он позволит нам узнать сколько символов текста поместится в указанную нами ширину.

Перепишем класс DrawView:

В конструкторе DrawView вызываем метод breakText. На вход передаем:

— текст
— true, означает что пойдем по тексту вперед, начиная с первого символа. Если false, то пойдем с конца.
— ширину, которая будет ограничивать текст
— массив, для получения точного значения ширины

Метод breakText возвращает кол-во символов.

Т.е. мы у объекта Paint спрашиваем, сколько символов указанного текста text влезет в указанную ширину maxWidth. Ответ мы получаем в переменную cnt. А в массив measuredWidth также попадает точная ширина урезанного текста, для удобства сохраним ее в переменную realWidth.

В onDraw выводим текст с полученными данными, искомый текст и две полосы для наглядности. Синяя полоса покажет точную ширину (realWidth) урезанного текста, а зеленая покажет лимит (maxWidth), который мы задавали.

maxWidth у нас равен 350. Метод breakText выяснил, что из указанного текста в 350 px влезет лишь 9 символов и они займут 330 px по ширине.

Синяя полоса показывает ширину урезанного текста. Видно что над этой полосой 9 символов (включая пробел).

Зеленая полоса показала лимит, который мы ставили — 350.

Среди методов измерения также есть метод getTextBounds, который позволит получить вам прямоугольник, в который заключен текст.

Рассмотрим возможность использования типов и стилей шрифтов.

Перепишем класс DrawView:

В onDraw мы выводим один и тот же текст, используя различные типы и стили шрифта. Для этого используем метод setTypeface, который требует на вход Typeface. Создать Typeface можно методом create, который требует на вход тип и стиль.

Сначала используем шрифт по умолчанию, затем строим различные комбинации

MONOSPACE – моноширинный, т.е. ширина всех символов одинакова

SERIF – шрифт с засечками

DEFAULT — шрифт по умолчанию

Кроме системных шрифтов, существует возможность использовать свои шрифты. Для этого вместо метода Typeface.create необходимо использовать другие его разновидности. Например createFromAsset. Помещаете ваш шрифт в папку assets и в методе createFromAsset указываете имя файла.

Рассмотрим еще несколько методов форматирования текста.

Перепишем класс DrawView:

setTextScaleX – позволяет растянуть/сжать текст

Прочее

Метод drawPosText позволяет при выводе раскидать текст посимвольно по различным точкам

Перепишем класс DrawView:

В конструкторе создаем массив pos. В нем указаны координаты точек, по которым поочередно будут раскиданы символы текста.

В onDraw вызываем drawPosText и передаем ему текст и массив.

Методы измерения можно использовать не только в рисовании. Вы можете для обычного TextView получить объект Paint методом getPaint, и далее уже вызывать необходимые вам методы. А метод setTypeface (для задания шрифта) у TextView есть свой.

На следующем уроке:

— используем PathMeasure для работы c Path

Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

Читайте также:  Unlock phone with android

— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Источник

Android Paint:.measureText () против getTextBounds()

Я измеряю текст с помощью Paint.getTextBounds() , так как я заинтересован в получении высоты и ширины текста, который будет отображаться. Однако фактический текст, отображаемый всегда немного шире, чем .width() на Rect информация заполняется getTextBounds() .

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

почему они разной ширины? Как я могу правильно получить высоту а ширина? Я имею в виду, я can использовать .measureText() , но тогда я не знаю, должен ли я доверять .height() возвращено getTextBounds() .

по запросу, вот минимальный код для воспроизведения проблемы:

вывод показывает, что разница не только становится больше 1 (и не является ошибкой округления в последнюю минуту), но и, похоже, увеличивается с размером (я собирался сделать больше выводов, но он может быть полностью зависимым от шрифта):

7 ответов

вы можете сделать то, что я сделал, чтобы проверить такую проблему:

изучение исходного кода Android, Paint.источник java, см. Оба метода measureText и getTextBounds. Вы узнаете, что measureText вызывает native_measureText, а getTextBounds вызывает nativeGetStringBounds, которые являются собственными методами, реализованными в C++.

таким образом, вы продолжаете изучать краску.cpp, который реализует оба.

native_measureText — > SkPaintGlue:: measureText_CII

nativeGetStringBounds — > SkPaintGlue:: getStringBounds

теперь ваше исследование проверяет, где эти методы отличаются. После некоторых проверок параметров оба вызова функции SkPaint:: measureText в Skia Lib (часть Android), но оба они вызывают разные перегруженные формы.

копаясь дальше в Skia, я вижу, что оба вызова приводят к одному вычислению в одной и той же функции, только возвращают результат по-разному.

ответить вопрос: Оба ваших звонка делают одно и то же вычисление. Возможная разница результата заключается в том, что getTextBounds возвращает границы как целое число, в то время как measureText возвращает значение типа float.

Итак, вы получаете ошибку округления при преобразовании float в int, и это происходит в Paint.cpp в SkPaintGlue::doTextBounds в вызове функции SkRect:: roundOut.

разница между вычисленной шириной этих двух вызовов может быть максимальной 1.

EDIT 4 Oct 2011

что может быть лучше, чем визуализация. Я приложил усилия, для собственного изучения, и для заслуженной награды:)

это размер шрифта 60, красным цветом —границы прямоугольник, фиолетовый-результат measureText.

видно, что левая часть границ начинается с нескольких пикселей слева, а значение measureText увеличивается на это значение как слева, так и справа. Это нечто! называется значением AdvanceX глифа. (Я обнаружил это в источниках Skia в SkPaint.cpp)

таким образом, результат теста заключается в том, что measureText добавляет некоторое предварительное значение к тексту с обеих сторон, в то время как getTextBounds вычисляет минимальные границы, где данный текст будет соответствовать.

надеюсь, что этот результат вам пригодится.

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

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

ответ мыши велик. И вот описание реальной проблемы:—10—>

короткий простой ответ заключается в том, что Paint.getTextBounds(String text, int start, int end, Rect bounds) возвращает Rect , которая не начинается с (0,0) . То есть, чтобы получить фактическую ширину текста, которая будет установлена путем вызова Canvas.drawText(String text, float x, float y, Paint paint) С то же самое Paint object from getTextBounds () вы должны добавить левую позицию Rect. Что-то вроде этого:—10—>

обратите внимание на это bounds.left — это ключ от проблема.

таким образом, вы получите ту же ширину текста, что и при использовании Canvas.drawText() .

и та же функция должна быть для получения height текст:

P. s.: Я не тестировал этот точный код,но протестировал концепцию.

более подробное объяснение дано в этой ответ.

Извините, что снова отвечаю на этот вопрос. Мне нужно было вставить изображение.

Я думаю, что результаты @mice найдены missleading. Наблюдения могут быть правильными для размера шрифта 60, но они становятся гораздо более разными, когда текст меньше. Например. Значение 10px. В этом случае текст фактически выводится за рамки.

Читайте также:  Как увеличить прошивку андроида

исходный код скриншота:

предупреждение: данное решение не является 100% точным с точки зрения определения минимальной ширины.

Я также выяснял, как измерить текст на холсте. После прочтения отличного поста от mice у меня возникли проблемы с измерением многострочного текста. Нет очевидного способа из этих вкладов, но после некоторых исследований я столкнулся с классом StaticLayout. Он позволяет измерять многострочный текст (текст с «\n») и настраивать гораздо больше свойств вашего текста через связанную краску.

вот фрагмент, показывающий, как измерить многострочный текст:

wrapwitdh может определить, хотите ли вы ограничить многострочный текст определенной шириной.

С момента StaticLayout.getWidth () возвращает только эту boundedWidth вам нужно сделать еще один шаг, чтобы получить максимальную ширину, требуемую многострочным текстом. Вы можете определить ширину каждой линии, а максимальная ширина-наибольшая ширина линии курс:

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

после этого вы можете позвонить:

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

вот как я рассчитал реальные размеры для первой буквы (вы можете изменить заголовок метода в соответствии с вашими потребностями, т. е. вместо char[] использовать String ):

обратите внимание, что я использую TextPaint вместо исходного класса Paint.

Источник

Класс Canvas

Класс android.graphics.Canvas (Холст) предоставляет методы для рисования, которые отображают графические примитивы на исходном растровом изображении. При этом надо сначала подготовить кисть (класс Paint), который позволяет указывать, как именно графические примитивы должны отображаться на растровом изображении (цвет, обводка, стиль, сглаживание шрифта и т.д.).

Android поддерживает полупрозрачность, градиентные заливки, округлённые прямоугольники и сглаживание. Из-за ограниченных ресурсов векторная графика пока что не поддерживается, вместо этого используется традиционная растровая перерисовка.

Canvas работает с пикселями, поэтому следует заботиться о конвертации единиц dp в px и наоборот при необходимости. Начало координат находится в левом верхнем углу.

Получить доступ к холсту можно через объект Bitmap или компонент View. Очень часто разработчики создают свой собственный компонент, наследуясь от View, и рисуют на его холсте для реализации своих замыслов.

Методы

Ниже представлены некоторые методы класса Canvas, которые что-то рисуют.

  • drawARGB()/drawRGB()/drawColor(). Заполняет холст сплошным цветом.
  • drawArc(). Рисует дугу между двумя углами внутри заданной прямоугольной области.
  • drawBitmap(). Рисует растровое изображение на холсте. Вы можете изменять внешний вид целевой картинки, указывая итоговый размер или используя матрицу для преобразования.
  • drawBitmapMesh(). Рисует изображение с использованием сетки, с помощью которой можно управлять отображением итоговой картинки, перемещая точки внутри неё.
  • drawCircle(). Рисует круг/окружность с определённым радиусом вокруг заданной точки.
  • drawLine(s)(). Рисует линию (или последовательность линий) между двумя точками.
  • drawOval(). Рисует овал на основе прямоугольной области.
  • drawPaint(). Закрашивает весь холст с помощью заданного объекта Paint.
  • drawPath(). Рисует указанный контур, используется для хранения набора графических примитивов в виде единого объекта.
  • drawPicture(). Рисует объект Picture внутри заданного прямоугольника.
  • drawPoint(). Рисует точку в заданном месте.
  • drawPosText(). Рисует текстовую строку, учитывая смещение для каждого символа.
  • drawRect(). Рисует прямоугольник.
  • drawRoundRect(). Рисует прямоугольник с закруглёнными углами.
  • drawText(). Рисует текстовую строку на холсте. Шрифт, размер, цвет и свойства отображения текста задаются в соответствующем объекте Paint.
  • drawTextOnPath(). Рисует текст, который отображается вокруг определённого контура.
  • drawVertices(). Рисует набор треугольников в виде совокупности вершинных (вертексных) точек.
  • rotate() и restore(). Вращение холста
  • Методы scale() и translate(). Изменение и перемещение координатной системы

Мы уже изучали основы рисования в первом месяце обучения (Работаем с графикой. Основы). Можно вернуться к этому проекту, закомментировать код вывода графики и продолжить изучение рисования при помощи методов класса Canvas.

Метод drawArc()

В API 21 появилась перегруженная версия метода, в котором можно указать координаты двух точек вместо RectF.

Метод drawArc() позволяет рисовать дуги и сектора. Ниже приводится код для трёх вариантов: сектор с заливкой (похож на PacMan), сектор без заливки (контур) и часть дуги:

Метод drawBitmap()

Вывести готовое изображение просто.

Метод drawCircle()

Первые два аргумента определяют координаты центра окружности/круга, следующий аргумент — её радиус в пикселах, последний — объект Paint. В зависимости от выбранного стиля кисти можно нарисовать закрашенный круг или только окружность.

Нарисуем зелёный круг.

drawLine(s)()

Простой метод — указываем начальные и конечные координаты отрезка.

Читайте также:  Как управлять android tv через алису

Метод drawOval()

Метод drawOval() рисует овалы. Естественно, если вы зададите одинаковые размеры ширины и высоты, то получите круг/окружность.

Если вам нужно наклонить овал в ту или иную сторону, то поверните холст на требуемый угол с помощью метода rotate(). Не забудьте потом повернуть холст обратно, что следующие фигуры выводились нормально.

Повернём синий овал из предыдущего примера:

В API 21 появилась перегруженная версия метода, в котором можно указать координаты двух точек вместо RectF:

Метод drawPaint()

Метод позволяет закрасить весь холст одним цветом.

Метод drawRect()

У метода существует три перегруженные версии для рисования прямоугольника. Рассмотрим один из них:

Метод drawRoundRect()

Для рисования прямоугольников с закруглёнными углами используется метод drawRoundRect (RectF rect, float rx, float ry, Paint paint).

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

Реализуем три разных способа:

В API 21 появилась перегруженная версия метода, в котором можно указать координаты двух точек вместо RectF.

Метод drawPath()

Для рисования соединённых отрезков можно использовать метод drawPath(), указав в параметрах настройки для рисования и массив координат точек. Для удобства добавим в класс Draw2D новый класс Pt, который позволит быстро создать массив точек с заданными координатами. Далее настраиваем объекты для рисования и формируем путь через созданный массив. В результате получим кошкин дом.

Путь можно составлять не только из точек, но и из фигур, например, дуг. Сначала формируем дугу, добавляем её в путь при помощи метода Path.addArc(), повторяем операцию снова несколько раз, а в конце выводим окончательный вариант:

Можно нарисовать символ парашюта:

Метод drawPoint()

Простой метод для рисования точки в нужно месте указанной кистью. Для координат используются значения типа float.

Метод drawText()

С помощью метода drawText() можно выводить текст в заданной позиции. Добавим сначала несколько эффектов, чтобы казалось, что текст парит над поверхностью:

Центрируем текст

Есть небольшая тонкость, если вам захочется вывести текст в центре холста. Проблем с вычислением центра холста и размером текста нет. Центр можно найти, разделив пополам значения ширины и высоты холста. А ширину и высоту текста можно узнать через метод кисти getTextBounds(), который возвращает ограничивающий прямоугольник.

Но вычисление ширины текста через textBounds.width(); приводит к небольшому смещению. Лучше воспользоваться методом кисти measureText(). Тогда текст отцентрируется точнее.

Пример на Kotlin с дополнительной информацией.

Методы rotate() и restore()

Холст во время рисования можно вращать. Во многих ситуациях такой приём менее затратный по ресурсам, чем рисование самого объекта под углом. Суть в следующем: вы поворачиваете холст на нужный градус, рисуете фигуру, а затем возвращаете холст на место при помощи метода restore(), чтобы следующие фигуры рисовались в ожидаемых местах. Иначе остальные фигуры будут рисоваться уже относительно поворота.

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

Вращение происходит вокруг начальной точки холста (0, 0). Но можно также использовать перегруженную версию метода rotate(float degrees, float px, float py), в которой можно указать координаты точки поворота.

Методы scale() и translate()

Стандартная система координат начинает свой отсчёт с верхнего левого угла. Иногда, для рисования сложных фигур удобнее назначить свою систему координат. Например, для рисования циферблата часов удобнее рисовать относительно центра экрана в диапазоне от -1 до 1.

Чтобы установить свою систему координат, нужно произвести трансформацию. В следующем примере мы установим координаты в диапазоне от 0 до 10 и нарисуем график в стандартном виде из точки 0,0 в левом нижнем углу в точку 10,10 в верхнем правом углу.

Для наглядности я добавил на оси несколько точек. Следует обратить внимание, что мы задали диапазон от 0 до 10 и все размеры должны масштабироваться в новых величинах, в том числе и ширина обводки в методе setStrokeWidth(). Поэтому значения должны быть достаточно маленькими, иначе толщина обводки может просто оказаться больше самой фигуры. Кстати, в некоторых случаях с текстом и другими методами рисование масштабирование может сыграть злую шутку и дробные значения не позволят увидеть текст и некоторые линии. В этих случаях приходиться создавать цепочку преобразований, когда временно масштаб увеличивается до нормальных размеров, рисуется текст с подходящим размером шрифта, затем опять всё уменьшается и т.д. Это долгая история.

Источник

Оцените статью