Android如何制作传统蒙文字体TextView

How to make a traditional Mongolian script TextView in Android

如何为 Android 应用制作垂直(从左到右换行)蒙古文字 TextView?

背景

Android 对世界上的许多语言都有很好的支持,甚至包括阿拉伯语和希伯来语等 RTL 语言。但是,没有内置对像 traditional Mongolian (which is still very much alive in Inner Mongolia and not to be confused with Cyrillic Mongolian 这样的自上而下语言的支持。下图显示了为清楚起见添加了英文的文本方向。

由于 Android 中未内置此功能,这使得应用程序开发的几乎每个方面都变得极其困难。网上的信息也非常非常少。 (其中一个few related SO questions连一个好的答案都没有。) 有不少传统蒙语的app开发者,但不管是出于商业原因还是其他原因,他们似乎都没有将自己的代码开源。

由于这些困难,我想提出一系列 Whosebug 问题,这些问题可以作为收集与传统蒙古语应用程序开发相关的一些较难编程问题的答案的中心位置。即使您不懂蒙古语,您帮助审查代码、提出评论和问题、给出答案甚至对问题进行投票也将不胜感激。

蒙古语垂直 TextView

一个蒙文TextView需要具备以下条件:

(TextView支持蒙古文字体不是绝对要求,TypeFace可以稍后设置,但在使用多个TextView时方便。)

我的答案如下,但我欢迎其他解决此问题的方法。

本系列其他相关问题:

iOS:

更新

我最终开发了一个垂直脚本 MongolTextView from scratch. It is available as a part of mongol-library

以下解决方案的问题是镜像字体中未包含的任何字符(尤其是中文)将显示为反向。

旧答案

蒙文字体的字形方向都与英文相同,即从左到右。这允许将蒙古语单词添加到英语、中文或西里尔文字中(唯一的问题是这些单词是“躺下”而不是它们应该“站立”的)。

顺时针旋转 TextView 90 度会使其垂直,但换行方向错误(旋转后从右到左而不是从左到右)。换行方向问题可以通过水平翻转或镜像 TextView 来解决,但是所有的字形都被镜像了。最后一个问题可以通过从垂直镜像字体开始解决(可以通过使用 FontForge 等开源软件编辑现有字体来实现)。下图说明了该过程:

旋转和翻转可以通过扩展 TextView 并覆盖 onDraw()onMeasure() 方法来完成:

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

在您的 xml 布局中使用扩展 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_marginlayout_gravity 如果您牢记旋转,则可以正常工作,但是 paddinggravity 的行为很奇怪。因此,使用 wrap_content 并避免使用 paddinggravity 似乎效果最好。通过将 MongolTextView 放在 FrameLayout 中并使用 layout_marginlayout_gravity.
  • 可以实现相同的效果
  • 此解决方案不处理呈现 Unicode 文本。您要么需要使用非 Unicode 文本(不鼓励),要么需要在您的应用程序中包含渲染引擎。 (Android 目前不支持 OpenType smartfont 渲染。希望这会在未来改变。iOS,相比之下确实支持复杂的文本渲染字体。)参见 this link Unicode 蒙古文渲染引擎示例。