3

Androidアプリで垂直モンゴル語スクリプトの水平スクロールListViewを作成するにはどうすればよいですか?

バックグラウンド

Android は、アラビア語やヘブライ語などの RTL 言語を含め、世界中の多くの言語をかなり適切にサポートしています。ただし、伝統的なモンゴル語の​​ような上から下までの言語の組み込みサポートはありません(内モンゴルではまだ非常に生きており、キリルモンゴル語と混同しないでください)。次の図は、わかりやすくするために英語を追加したテキストの方向を示しています。

ここに画像の説明を入力

この機能は Android に組み込まれていないため、アプリ開発のほぼすべての側面が非常に困難になります。これは特に、Android でそのままではサポートされていない水平の ListView に当てはまります。また、オンラインで入手できる情報は非常に少ないです。伝統的なモンゴル語の​​アプリ開発者は数多くいますが、商業的な理由かどうかにかかわらず、コードをオープン ソース化していないようです。

これらの困難のため、伝統的なモンゴルのアプリ開発に関連するいくつかのより困難なプログラミングの問題に対する回答を収集するための中心的な場所として役立つ一連の StackOverflow の質問を作成したいと思います。モンゴル語の​​読み書きができなくても、コードのレビュー、コメントや質問の作成、回答の提供、さらには質問への賛成投票を手伝っていただければ幸いです。

垂直スクリプトを使用したモンゴル語の​​水平スクロール ListView

モンゴル語の​​ ListView には、次の要件が必要です。

  • 左から右に水平にスクロールします
  • タッチ イベントは、通常の ListView と同じように機能します
  • カスタム レイアウトは、通常の ListView と同じようにサポートされます

また、モンゴルの TextViewがサポートするすべてのものをサポートする必要があります。

  • 伝統的なモンゴル語フォントをサポート
  • テキストを上から下に垂直に表示します
  • 行の折り返しは左から右に進みます。
  • スペースで改行する(英語と同じ)

以下の画像は、モンゴル語の​​ ListView に必要な基本機能を示しています。

ここに画像の説明を入力

私の答えは以下ですが、この問題を解決する他の方法を歓迎します。

このシリーズのその他の関連する質問:

iOS:

4

1 に答える 1

2

アップデート

RecyclerView には水平レイアウトがあります。そのため、これらのいずれかに垂直モンゴル語 TextView を配置するのは比較的簡単です。からの例を次に示しますmongol-library

ここに画像の説明を入力

a を使用して水平方向にスクロールするリストを作成する一般的な解決策については、この回答を参照してください。RecyclerView

古い答え

Android API で水平方向の ListView が提供されないのは非常に残念です。ただし、それらを行う方法について説明している StackOverflow Q&A が多数あります。いくつかのサンプルを次に示します。

しかし、実際にこれらの提案を実装し、モンゴル語の​​縦書きを取り入れようとしたとき、私はひどい時間を過ごしました. 検索のどこかで、少し異なる答えを見つけました。レイアウト全体を回転させるクラスでした。これは、ViewGroup を拡張することで実現しました。このようにして、何でも (ListView を含む) を ViewGroup に入れることができ、回転されます。すべてのタッチイベントも機能します。

モンゴル語の​​ TextViews に関する回答で説明したように、単にモンゴル語の​​テキストを回転させるだけでは十分ではありません。すべての ListView アイテム (または ViewGroup 内の他のテキスト要素) が 1 行のみの場合はこれで十分ですが、複数の行を回転すると行の折り返しが間違った方向に進みます。ただし、次の図に示すように、レイアウトを水平方向にミラーリングし、垂直方向にミラーリングされたフォントを使用すると、これを克服できます。

ここに画像の説明を入力

回転した ViewGroup コードを調整して、水平方向のミラーリングも行いました。

public class MongolViewGroup extends ViewGroup {

    private int angle = 90;
    private final Matrix rotateMatrix = new Matrix();
    private final Rect viewRectRotated = new Rect();
    private final RectF tempRectF1 = new RectF();
    private final RectF tempRectF2 = new RectF();
    private final float[] viewTouchPoint = new float[2];
    private final float[] childTouchPoint = new float[2];
    private boolean angleChanged = true;

    public MongolViewGroup(Context context) {
        this(context, null);
    }

    public MongolViewGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
        setWillNotDraw(false);
    }

    public View getView() {
        return getChildAt(0);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final View view = getView();
        if (view != null) {
            measureChild(view, heightMeasureSpec, widthMeasureSpec);
            setMeasuredDimension(resolveSize(view.getMeasuredHeight(), widthMeasureSpec),
                    resolveSize(view.getMeasuredWidth(), heightMeasureSpec));
        } else {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        if (angleChanged) {
            final RectF layoutRect = tempRectF1;
            final RectF layoutRectRotated = tempRectF2;
            layoutRect.set(0, 0, right - left, bottom - top);
            rotateMatrix.setRotate(angle, layoutRect.centerX(), layoutRect.centerY());
            rotateMatrix.postScale(-1, 1);
            rotateMatrix.mapRect(layoutRectRotated, layoutRect);
            layoutRectRotated.round(viewRectRotated);
            angleChanged = false;
        }
        final View view = getView();
        if (view != null) {
            view.layout(viewRectRotated.left, viewRectRotated.top, viewRectRotated.right,
                    viewRectRotated.bottom);
        }
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {

        canvas.save();
        canvas.rotate(-angle, getWidth() / 2f, getHeight() / 2f);
        canvas.scale(-1, 1);
        super.dispatchDraw(canvas);
        canvas.restore();
    }

    @Override
    public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
        invalidate();
        return super.invalidateChildInParent(location, dirty);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        viewTouchPoint[0] = event.getX();
        viewTouchPoint[1] = event.getY();
        rotateMatrix.mapPoints(childTouchPoint, viewTouchPoint);
        event.setLocation(childTouchPoint[0], childTouchPoint[1]);
        boolean result = super.dispatchTouchEvent(event);
        event.setLocation(viewTouchPoint[0], viewTouchPoint[1]);
        return result;
    }


}

ただし、モンゴル語の​​垂直ミラー フォントは、別の場所に設定する必要があります。それを行うには、カスタム TextView を作成するのが最も簡単だと思います。

public class MongolNonRotatedTextView extends TextView {

    // This class does not rotate the textview. It only displays the Mongol font.
    // For use with MongolLayout, which does all the rotation and mirroring.

    // Constructors
    public MongolNonRotatedTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    public MongolNonRotatedTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public MongolNonRotatedTextView(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/MongolMirroredFont.ttf");
         setTypeface(tf);

    }
}

次に、カスタム ListView 項目 xml レイアウトは次のようになります。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rlListItem"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

        <com.example.MongolNonRotatedTextView
            android:id="@+id/tvListViewText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"/>

</RelativeLayout>

既知の問題点:

  • 下の画像を注意深く見ると、テキストの周りにかすかな水平線と垂直線が見えます。この画像は別の開発者のアプリからのものですが、回転した ViewGroup を使用すると、アプリで同じ成果物が得られます (ただし、回転した TextViewを使用する場合はそうではありません)。誰かがこれらがどこから来ているか知っているなら、私にコメントを残してください!

ここに画像の説明を入力

  • このソリューションは、Unicode テキストのレンダリングを扱いません。非 Unicode テキストを使用する必要があるか (非推奨)、アプリにレンダリング エンジンを含める必要があります。(現時点では、Android は OpenType スマートフォント レンダリングをサポートしていません。これが将来変更されることを願っています。比較すると、iOS は複雑なテキスト レンダリング フォントをサポートしています。) Unicode モンゴル語レンダリング エンジンの例については、このリンクを参照してください。
于 2015-04-20T15:20:00.113 に答える