How do you make vertical (with left-to-right line wrapping) Mongolian script TextViews for Android apps?
Android has fairly good support for many of the world's languages, even RTL languages like Arabic and Hebrew. However, there is no built in support for top-to-bottom languages like traditional Mongolian (which is still very much alive in Inner Mongolia and not to be confused with Cyrillic Mongolian). The following graphic shows the text direction with English added for clarity.
Since this functionality is not built into Android, it makes almost every single aspect of app development extremely difficult. There is also very, very little information available online. (One of the few related SO questions does not even have a good answer.) There are a number of app developers for traditional Mongolian, but whether it is for commercial reasons or otherwise, they do not seem to make their code open source.
Because of these difficulties I would like to make a series of StackOverflow questions that can serve as a central place to collect answers for some of the more difficult programming problems related to traditional Mongolian app development. Even if you are not literate in Mongolian, your help reviewing the code, making comments and questions, giving answers or even up-voting the question would be appreciated.
A Mongolian TextView needs to have the following requirements:
(Having the TextView support the Mongolian font is not an absolute requirement since the TypeFace can be set later, but it is a convenience when many TextViews are being used.)
My answer is below but I welcome other ways of solving this problem.
iOS:
I ended up developing a vertical script MongolTextView
from scratch. It is available as a part of mongol-library
.
The problem with the solution below is that any characters not included in the mirrored font (Chinese notably) will appear backward.
Mongolian fonts are all made with the the orientation of the glyphs in the same direction as English, that is, left to right. This allows Mongolian words to be added to English, Chinese, or Cyrillic text (the only problem being that the words are "laying down" rather than "standing up" as they should).
Rotating the TextView 90 degrees clockwise will make it vertical, but the line-wrap goes the wrong direction (right-to-left instead of left-to-right after the rotation). The line-wrap direction problem can be solved by horizontally flipping or mirroring the TextView, but then all of the glyphs are mirrored. This final problem can be solved by starting with a vertically mirrored font (something that is possible to make by editing an existing font with open source software like FontForge). The following graphic illustrates the process:
The rotating and flipping can be done by extending TextView and overriding the onDraw()
and onMeasure()
methods:
public class MongolTextView extends TextView {
private TextPaint textPaint;
// Constructors
public MongolTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public MongolTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MongolTextView(Context context) {
super(context);
init();
}
// This class requires the mirrored Mongolian font to be in the assets/fonts folder
private void init() {
Typeface tf = Typeface.createFromAsset(getContext().getAssets(),
"fonts/MongolFontMirrored.ttf");
setTypeface(tf);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// swap the height and width
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
}
@Override
protected void onDraw(Canvas canvas) {
textPaint = getPaint();
textPaint.setColor(getCurrentTextColor());
textPaint.drawableState = getDrawableState();
canvas.save();
// flip and rotate the canvas
canvas.translate(getWidth(), 0);
canvas.rotate(90);
canvas.translate(0, getWidth());
canvas.scale(1, -1);
canvas.translate(getCompoundPaddingLeft(), getExtendedPaddingTop());
getLayout().draw(canvas);
canvas.restore();
}
}
In your xml layout use the full name of your extended TextView:
<com.example.MongolTextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:text="@string/title_string" />
layout_margin
and layout_gravity
work ok if you keep the rotation in mind, but padding
and gravity
act strangely. So it seems to work best to use wrap_content
and avoid using padding
and gravity
. The same effect can be achieved by putting the MongolTextView in a FrameLayout and using layout_margin
and layout_gravity
.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With