问题
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.
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:
- How to make a traditional Mongolian script EditText in Android
- How to make a traditional Mongolian script ListView in Android
- More to come... (Toast, Dialog, Menu)
iOS:
- How do you make a vertical text UILabel and UITextView for iOS in Swift?
回答1:
Update
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.
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:
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
andlayout_gravity
work ok if you keep the rotation in mind, butpadding
andgravity
act strangely. So it seems to work best to usewrap_content
and avoid usingpadding
andgravity
. The same effect can be achieved by putting the MongolTextView in a FrameLayout and usinglayout_margin
andlayout_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.
来源:https://stackoverflow.com/questions/29739720/how-to-make-a-traditional-mongolian-script-textview-in-android