How to make a traditional Mongolian script TextView in Android
Asked Answered
A

1

8

How do you make vertical (with left-to-right line wrapping) Mongolian script TextViews for Android apps?

Background

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.

enter image description here

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.

Mongolian Vertical TextView

A Mongolian TextView needs to have the following requirements:

  • Supports a traditional Mongolian font
  • Displays text vertically from top to bottom
  • Line wrapping goes from left to right.
  • Line breaks occur at a space (same as English)

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

Other related questions in this series:

iOS:

Automobile answered 20/4, 2015 at 5:10 Comment(0)
A
7

Update

I ended up developing a vertical script MongolTextView from scratch. It is available as a part of mongol-library.

enter image description here

The problem with the solution below is that any characters not included in the mirrored font (Chinese notably) will appear backward.

Old answer

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:

enter image description here

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

Known issues:

  • 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.
  • This solution does not deal with rendering the Unicode text. Either you need to use non-Unicode text (discouraged) or you need to include a rendering engine in your app. (Android does not support OpenType smartfont rendering at this time. Hopefully this will change in the future. iOS, by comparison does support complex text rendering fonts.) See this link for a Unicode Mongolian rendering engine example.
Automobile answered 20/4, 2015 at 5:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.