- PVSM.RU - https://www.pvsm.ru -
В последнее время перед разработчиками все чаще ставится задача использовать символ рубля в тексте. Однако, символ рубля был утвержден относительно недавно [1], символ получил свой код в стандате Unicode еще позже [2]. Естественно, гарнитура Roboto на текущих платформах еще не содержит знака рубля.
Создать гарнитуру состоящую из одного символа рубля с кодом U+20BD [3], и при отрисовке текста для символов рубля использовать эту гарнитуру.
В ОС Android существует механизм маркировки строк специальными объектами влияющими на рендеринг текста TextView. Например, существуют объекты для переопределения цвета заливки [4]/фона [5], стиля [6] или всего сразу [7] (полный список [8] встроенных в Android маркеров). Об этом механизме уже писале на хабре здесь [9] и здесь [10].
За основу будущей гарнитуры я взял готовое решение от Артемия Лебедева, о котором писали [11] некоторое время назад на Хабре. Эта гарнитура состоит из различных начертаний символа рубля закрепленных за символами латинского алфавита (от строчной a до s).

Я выбрал глиф, который закреплен за буквой i (
). Как мне кажется, он наиболее подходит для использования с гарнитурой Roboto.
Для редактирования гарнитуры, я использовал замечательное приложение Glyphs [12]. Я удалил все глифы из гарнитуры и оставил только выбранный. Ему я назначил код U+20BD. Следующий шаг — экспорт в ttf.
В итоге у меня получилось так [13].
Конечно, можно было бы отредактировать глиф заглавной Р, дорисовав палочку, однако, я не чувствую в себе уверенности в этом деле. Уж больно много нюансов. Если кто-то может сделать это, с удовольствием приму ваш pull request.
Для начала создадим проект из шаблона. Я использовал шаблон с Blank Activity из комплекта Android Studio, activity назвал MainActivity.
Разметка для MainActivity выглядит так выглядит так:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<EditText
android:id="@+id/main_price_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="numberDecimal"
tools:hint="@string/main_price_hint"
/>
</LinearLayout>
Тут все просто, создаем LinearLayout с одним потомком EditText. Свойство hint у EditText мы задаем с namespace tools, для того что бы подсказка отображалась только в предпросмотре. В программе мы будем задавать подсказку программно.
В MainActivity#onCreate мы должны составить spanned [14] string, в котором все знаки рубля будут маркированны TypefaceSpan [15], который позволяет изменить гарнитуру для отрисовки заданных символов. Тут нас ожидает маленькая неприятность: TypefaceSpan можно создать только с font-family — названием шрифта из набора системы. К счастью, судя по исходному коду TypefaceSpan [16], этот подход не обусловлен техническими возможностями системы рендеринга текста, что позволяет нам создать собственную версию TypefaceSpan, который поддерживает задание гарнитуры непосредственно объектом Typeface [17]. Копируем
package me.pepyakin.roublesign;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.text.TextPaint;
import android.text.style.MetricAffectingSpan;
public class TypefaceSpan2 extends MetricAffectingSpan {
private final Typeface mTypeface;
public TypefaceSpan2(Typeface typeface) {
mTypeface = typeface;
}
@Override
public void updateDrawState(TextPaint ds) {
apply(ds, mTypeface);
}
@Override
public void updateMeasureState(TextPaint paint) {
apply(paint, mTypeface);
}
private static void apply(Paint paint, Typeface tf) {
int oldStyle;
Typeface old = paint.getTypeface();
if (old == null) {
oldStyle = 0;
} else {
oldStyle = old.getStyle();
}
int fake = oldStyle & ~tf.getStyle();
if ((fake & Typeface.BOLD) != 0) {
paint.setFakeBoldText(true);
}
if ((fake & Typeface.ITALIC) != 0) {
paint.setTextSkewX(-0.25f);
}
paint.setTypeface(tf);
}
}
Осталось только сделать маркировку текста с помощью объявленного выше TypefaceSpan2, с необходимой нам гарнитурой.
String priceHint = getString(R.string.main_price_hint);
final Typeface roubleSupportedTypeface =
Typeface.createFromAsset(getAssets(), "fonts/rouble2.ttf");
SpannableStringBuilder resultSpan = new SpannableStringBuilder(priceHint);
for (int i = 0; i < resultSpan.length(); i++) {
if (resultSpan.charAt(i) == 'u20BD') {
TypefaceSpan2 roubleTypefaceSpan = new TypefaceSpan2(roubleSupportedTypeface);
resultSpan.setSpan(roubleTypefaceSpan, i, i + 1, 0);
}
}
Здесь мы загружаем шаблон нашей строки, содержащей символ рубля и гарнитуру с глифом рубля.
Затем создаем SpannableStringBuilder [18] на основе шаблона и с помощью setSpan [19] расставляем маркеры для смены гарнитуры.
Назначаем hint,
priceInput.setHint(resultSpan);
и готово!

Ссылка на исходники [20]
Автор: knott
Источник [21]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/razrabotka-pod-android/66014
Ссылки в тексте:
[1] был утвержден относительно недавно: http://ru.wikinews.org/wiki/%D0%91%D0%B0%D0%BD%D0%BA_%D0%A0%D0%BE%D1%81%D1%81%D0%B8%D0%B8_%D1%83%D1%82%D0%B2%D0%B5%D1%80%D0%B4%D0%B8%D0%BB_%D1%81%D0%B8%D0%BC%D0%B2%D0%BE%D0%BB_%D1%80%D1%83%D0%B1%D0%BB%D1%8F
[2] свой код в стандате Unicode еще позже: https://twitter.com/ken_lunde/status/430761051290759168
[3] U+20BD: http://www.fileformat.info/info/unicode/char/20bd/index.htm
[4] заливки: http://developer.android.com/reference/android/text/style/ForegroundColorSpan.html
[5] фона: http://developer.android.com/reference/android/text/style/BackgroundColorSpan.html
[6] стиля : http://developer.android.com/reference/android/text/style/StyleSpan.html
[7] всего сразу: http://developer.android.com/reference/android/text/style/TextAppearanceSpan.html
[8] полный список: http://developer.android.com/reference/android/text/style/package-summary.html
[9] здесь: http://habrahabr.ru/post/166351/
[10] здесь: http://habrahabr.ru/post/167343/
[11] писали: http://habrahabr.ru/post/48084/
[12] Glyphs: http://www.glyphsapp.com/
[13] так: https://github.com/pepyakin/roublesign/blob/master/app/src/main/assets/fonts/rouble2.ttf
[14] spanned: http://developer.android.com/reference/android/text/Spanned.html
[15] TypefaceSpan: http://developer.android.com/reference/android/text/style/TypefaceSpan.html
[16] исходному коду TypefaceSpan: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/text/style/TypefaceSpan.java
[17] Typeface: https://developer.android.com/reference/android/graphics/Typeface.html
[18] SpannableStringBuilder: https://developer.android.com/reference/android/text/SpannableStringBuilder.html
[19] setSpan: https://developer.android.com/reference/android/text/SpannableStringBuilder.html#setSpan(java.lang.Object, int, int, int)
[20] Ссылка на исходники: https://github.com/pepyakin/roublesign
[21] Источник: http://habrahabr.ru/post/231203/
Нажмите здесь для печати.