My application uses the unicode character \u2192 to display a right arrow within a TextView element. However, the arrow is shown at the very bottom line, but should be centered vertically:
However, if I print the unicode character using the standard output, everything is fine:
public class Main {
public static void main(String[] args) {
System.out.println("A" + Character.toString("\u2192".toCharArray()[0]));
}
}
How I can enforce the right arrow to be centered in the TextView, too? My TextView already uses android:gravity="center_vertical|left"
.
Update: I use Android Studio 3.0.1 and Android SDK 26. The XML code of the TextView:
<TextView
android:id="@+id/my_text_view"
android:layout_width="match_parent"
android:fontFamily="monospace"
android:gravity="center_vertical|left"
android:textSize="26sp" />
Filling the TextView in the code:
TextView textView = findViewById(R.id.my_text_view);
textView.setText("A" + Character.toString("\u2192".toCharArray()[0]) + "B");
Since Android's Roboto font doesn't seem to contain arrow glyphs, this would cause it to display a character from a fallback font if possible (though I couldn't find the documentation of this behavior). I'm guessing that the "fallback" arrow on your device is lying on the baseline for some reason.
However, there's a trick that might help you: You can include an image of the special character and insert the image into your output text.
First, add a new Drawable resource file (ic_arrow.xml
) in res/drawable
, and copy-paste this into it:
<vector android:alpha="0.78" android:height="24dp"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M3,12L21.5,12"
android:strokeColor="#000000" android:strokeWidth="1"/>
<path android:fillColor="#FF000000" android:pathData="M21,12L17,8"
android:strokeColor="#000000" android:strokeWidth="1"/>
<path android:fillColor="#FF000000" android:pathData="M21,12L17,16"
android:strokeColor="#000000" android:strokeWidth="1"/>
</vector>
Now, we'll need to embed the arrow image into a SpannableString that you can display in your TextView. I'll walk you through the (surprisingly many) lines of code that we'll need to accomplish this:
Get the Drawable resource so that we can make it the correct size before displaying it.
Drawable arrow = ContextCompat.getDrawable(this, R.drawable.ic_arrow);
Figure out what size the arrow needs to be, based on the font
metrics.
Float ascent = textView.getPaint().getFontMetrics().ascent;
This is negative (for reasons), so make it positive.
int h = (int) -ascent;
Finally, we can set the bounds of the Drawable to match the text
size.
arrow.setBounds(0,0,h,h);
Next, create a SpannableString initialized with our text. I just used *
for a placeholder here, but it could be any character (or a blank space). If you're planning to concatenate different bits together along with multiple arrow images, use a SpannableStringBuilder
for this.
SpannableString stringWithImage = new SpannableString("A*B");
Now, we can finally insert the image into the span (using a new
ImageSpan with our "arrow" image, aligned with the baseline).
The 1
and 2
are zero-based start and end indices (telling where
to insert the image), and SPAN_EXCLUSIVE_EXCLUSIVE
indicates that
the span doesn't expand to include inserted text.
stringWithImage.setSpan(new ImageSpan(arrow, DynamicDrawableSpan.ALIGN_BASELINE), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
Finally, we can display the text (including the custom arrow image):
textView.setText(stringWithImage);
Altogether, the code should look like this.
TextView textView = findViewById(R.id.my_text_view);
Drawable arrow = ContextCompat.getDrawable(this, R.drawable.ic_arrow);
Float ascent = textView.getPaint().getFontMetrics().ascent;
int h = (int) -ascent;
arrow.setBounds(0,0,h,h);
SpannableString stringWithImage = new SpannableString("A*B");
stringWithImage.setSpan(new ImageSpan(arrow, DynamicDrawableSpan.ALIGN_BASELINE), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(stringWithImage);
I wish Android had a better way to do this sort of thing, but at least it can be done somehow. The resulting TextView should look like this:
Try that:
SpannableString st = new SpannableString("A" + "\u2192" + "B");
st.setSpan(new RelativeSizeSpan(2f), 1, 2, 0);
textView.setText(st);
I know that however this doesn't completely answer.
Try another symbols with html entity encodings. Look at this link, maybe you find here more convenient right arrow for you but I chose this for example : ➔
String formula = "A ➔ B";
textView.setText(Html.fromHtml(formula));
also this third party lib maybe appropriate for you