当前位置: 首页 > 知识库问答 >
问题:

如何在Android中制作传统蒙古文脚本ListView

任昊阳
2023-03-14

如何在Android应用程序中为垂直蒙古语脚本水平滚动ListView?

Android对世界上许多语言都有相当好的支持,甚至包括阿拉伯语和希伯来语等RTL语言。但是,对于像传统蒙古语这样的自上而下的html" target="_blank">语言没有内置的支持(蒙古语在内蒙古仍然非常活跃,不要与西里尔蒙古语混淆)。下图显示了文字方向,为清晰起见,添加了英文。

由于Android没有内置这一功能,这使得应用程序开发的每一个方面都非常困难。水平列表视图尤其如此,Android中不支持开箱即用的列表视图。网上也只有非常非常少的信息。传统蒙古语有很多应用程序开发人员,但无论是出于商业原因还是其他原因,他们似乎都没有将代码开源。

由于这些困难,我想提出一系列StackOverflow问题,这些问题可以作为收集与传统蒙古应用程序开发相关的一些更困难的编程问题的答案的中心。即使您没有蒙古语文化,您的帮助审查代码,提出意见和问题,给出答案,甚至投票赞成的问题将不胜感激。

蒙古文ListView需要具备以下要求:

  • 从左到右水平滚动
  • 触摸事件的工作原理与正常的ListView相同
  • 自定义布局的支持与普通的ListView相同

还需要支持蒙古语文本视图支持的所有内容:

  • 支持传统蒙古文字体
  • 从上到下垂直显示文本
  • 换行从左到右
  • 换行符出现在空格处(与英文相同)

下图显示了蒙古语ListView应具备的基本功能:

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

  • 如何在Android中制作传统蒙古文文本视图
  • 如何在Android中制作传统蒙古文脚本EditText
  • 还有更多。。。(吐司、对话、菜单)

网间网操作系统:

  • 如何在Swift中为iOS制作垂直文本UILabel和UITextView?

共有1个答案

邹嘉荣
2023-03-14

RecyclerViews具有水平布局。因此,将一个垂直的蒙古语文本视图放在其中一个文本视图中是相对容易的。下面是来自蒙古图书馆的一个例子。

有关使用RecyclerView创建水平滚动列表的一般解决方案,请参见此答案。

很不幸的是,Android API不提供水平ListView。有一些StackOverflow Q

  • 如何在Android中创建水平列表视图

但是,当我真的试图实施这些建议以及合并蒙古文垂直文本时,我经历了一段糟糕的时光。在我的搜索中,我发现了一个稍微不同的答案。这是一个旋转整个布局的类。它通过扩展ViewGroup实现了这一点。通过这种方式,任何东西(包括ListView)都可以放入ViewGroup中并进行旋转。所有的触摸事件也都有效。

正如我在关于蒙古语文本视图的回答中所解释的,仅仅旋转蒙古语文本是不够的。如果每个ListView项(或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;
    }


}

不过,蒙古文垂直镜像字体仍需要在其他地方设置。我发现制作自定义文本视图最简单:

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>
  • 如果仔细观察下面的图像,可以看到文本周围有微弱的水平线和垂直线。尽管此图像来自另一个开发人员的应用程序,但当我使用旋转视图组时,我在应用程序中得到了相同的工件(但当我使用旋转文本视图时,却没有)。如果有人知道这些是从哪里来的,请给我留言
  • 此解决方案不处理呈现Unicode文本的问题。您需要使用非Unicode文本(不鼓励),或者需要在应用程序中包含渲染引擎。(Android目前不支持OpenType smartfont呈现。希望将来会有所改变。相比之下,iOS支持复杂的文本呈现字体。)有关Unicode蒙古文渲染引擎示例,请参见此链接

 类似资料:
  • 我的代码只有在我删除限制函数时才有效,我做错了什么? 错误为: TypeError:批量。查找(…)。limit不是D:\nodeprojects\mysite\server上的函数。js:281:19 at对象。(D:\nodeprojects\mysite\server.js:285:3)位于模块_在对象处编译(module.js:570:32)。模块_扩展。。模块处的js(模块js:579:

  • 给定文档结构: 如何按其分组并仅在计数处获取 使用下面的查询没有返回任何结果。谁能指出这里缺少了什么吗? 谢谢

  • 问题内容: 在我的应用中,我想用其他名称保存某个文件的副本(我从用户那里得到) 我真的需要打开文件的内容并将其写入另一个文件吗? 最好的方法是什么? 问题答案: 要复制文件并将其保存到目标路径,可以使用以下方法。 在API 19+上,你可以使用Java自动资源管理:

  • 我试图使我的Android项目的ListView,但不幸的是,当我导入这些库: 上面说这些是“未使用的导入语句”!所以我不能使用“setListAdapter()”函数或其他类似的函数。 我的代码是

  • 问题内容: 我使用python Selenium和Scrapy爬行网站。 但是我的剧本太慢了 我使用CSS SELECTOR而不是XPATH来优化时间。我改变了中间件 是selenium太慢还是我应该在“设置”中更改某些内容? 我的代码: 问题答案: 因此,您的代码在这里几乎没有缺陷。 当scrapy Selectors更快,更高效时,您可以使用硒来解析页面内容。 您为每个响应启动一个webdri

  • 我正在尝试为Android牛轧糖开发一个应用程序,我想在状态栏中显示一些信息/文本,生成一个Android服务例程。所以我的问题是,我不知道如何显示状态栏中的文本。 我添加了一个示例图像来显示我的确切意思(红圈)。我知道这是有可能的,因为我在play Store的一款电池监控器应用中看到了它。 我已经尝试了notificationbatch.builder,但我认为这不是正确的方法。也许是一个叠加