📜 ⬆️ ⬇️

We draw a ruble sign in the Android application

Recently, developers have increasingly been asked to use the ruble symbol in the text. However, the ruble symbol was approved relatively recently , the symbol received its code in the Unicode standard even later . Naturally, the Roboto headset on current platforms does not yet contain a ruble sign.

Idea

Create a headset consisting of one ruble symbol with code U + 20BD , and when drawing text for ruble symbols use this headset.

A little bit about Span

In Android, there is a mechanism for marking strings with special objects that affect the rendering of TextView text. For example, there are objects to override the fill color / background , style, or all at once (a complete list of markers embedded in Android). About this mechanism already wrote on Habré here and here .

Creating the desired headset

For the basis of the future headset, I took a ready-made solution from Artemy Lebedev, whom I wrote about some time ago on Habré. This headset consists of different styles of the ruble symbol assigned to the Latin alphabet characters (from lowercase a to s ).
')
List of all glyphs

I chose the glyph that is assigned to the letter i ( Ruble symbol ). As it seems to me, it is most suitable for use with the Roboto headset.
To edit the headset, I used the wonderful Glyphs app. I deleted all the glyphs from the headset and left only the selected one. I assigned him the code U + 20BD. The next step is exporting to ttf.
In the end, I did it .
Of course, it would be possible to edit the glyph of the capital P, having drawn the wand, however, I do not feel confident in this matter. It hurts a lot of nuances. If someone can do this, I will gladly accept your pull request.

Implementation

To begin, create a project from a template. I used the Blank Activity template from the Android Studio suite, an activity called MainActivity.
The markup for MainActivity looks like this:

<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> 


Everything is simple, we create LinearLayout with one descendant of EditText. We set the hint property of EditText with the namespace tools , so that the tooltip is displayed only in the preview. In the program we will set the hint programmatically.

In MainActivity#onCreate we need to make a spanned string, in which all the ruble signs will be labeled TypefaceSpan , which allows you to change the headset to draw the specified characters. Here we have a little trouble: TypefaceSpan can be created only with the font-family - the name of the font from the system set. Fortunately, judging by the TypefaceSpan source code , this approach is not due to the technical capabilities of the text rendering system, which allows us to create our own version of TypefaceSpan, which supports setting the headset directly with a Typeface object.

 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); } } 


It remains only to make the marking of the text using the TypefaceSpan2 announced above, with the headset we need.

 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); } } 


Here we load the template of our string containing the ruble symbol and a headset with the ruble glyph.
Then we create a SpannableStringBuilder based on the template and with the help of setSpan we arrange markers for changing the headset.

Assign hint,

 priceInput.setHint(resultSpan); 

and ready!
Finished result

Link to source

Source: https://habr.com/ru/post/231203/


All Articles