维语和中英文混排的思考(ltr 和 rtl)

3,480 阅读2分钟

[toc]

在 Andorid 开发中 不同语言的顺序是不同的,比如维语是从右到左的。下面来研究下混排模式下的显示。

以维语和英文为主,其他语言类似。

主显示顺序

对于 混排的 String 来说,顺序是确定的。当只有显示到 TextView 上是,支持 RTL 的情况下,顺序才会改变。

因此,可以对 String 进行判断,是 ltr 还是 rtl 显示的。

可以通过下面的函数来判断:

fun isRtl(string: String): Boolean {
    if (TextUtils.isEmpty(string)) {
        return false
    }
    string.forEachIndexed { index, char ->
        Logger.d("$index, ${Character.getDirectionality(char)}")
        when (Character.getDirectionality(char)) {
            Character.DIRECTIONALITY_RIGHT_TO_LEFT,
            Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC,
            Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING,
            Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE -> return true

            Character.DIRECTIONALITY_LEFT_TO_RIGHT,
            Character.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING,
            Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE -> return false
        }
    }
    return false
}

简单来说,就是从左往右判断第一个影响顺序的字符:如果是英文,则是 ltr。如果是维语字符,则是 rtl。

需要注意的是:数字,标点,空格不影响顺序。

比如下面几种情况:

val wy = "نى ئىزدەش"
val str1 = "hello $wy" //ltr -> hello $wy
val str2 = ":hello $wy" //ltr -> :hello $wy
val str3 = "$wy hello" //rtl -> hello $wy
val str4 = ":1$wy hello" //rtl -> hello $wy1:

上面四个字符串的显示顺序和显示结果。

字符串内部显示顺序

注意到上面最后一个字符串的显示,是 $wy1:。因为内部的显示顺序也会有有所不同。

在主顺序确定的前提下,内部顺序根据词组来决定。

ltr

add("hello $wy world") // ltr -> hello $wy world

比如对于上面的字符串,可以分为三个词,ltr 的顺序不变。这是简单的情况。

对于有符号的句子:

add("hello: $wy; world") //  -> ltr hello: $wy; world
add("hello: $wy; 2") // ltr -< hello: 2 ;$wy

对比上面两种情况,发现显示顺序有差异。简单来说,就是:

主方向确定情况下,内部也会出现 rtl。比如可以将上面的 hello:看作一个词组,因为里面不会出现影响顺序的字符。而 $wy; 2看作一个词组,从第一个字符开始到最后一个字符结束,内部词组 rtl,显示如上显示。

这里有个特例,我也没搞明白:

add("hello: $wy; 123;") // -> hello: 123 ;$wy ;

但维语后面出现仅出现字符时,顺序不变;但维语后面出现字符和数字时,顺序变为rtl。此时到最后一个字符结束,不影响后面词组的顺序。

rtl

内部词组的显示逻辑和上面类似,多测试可以得出结果。

遇到的问题

需要有一个 Textview 显示内容:搜索 “xxx”的维语文案。比如 $wy "hello"

即:

add("$wy \"hello\"") // rtl -> “hello” $wy
add("\"hello\" $wy") // lrt -> “hello” $wy

上面两个不同的文案,按照上面的分析,显示在 Textview 的结果是一致的。不满足要求显示的文案。

btn_custom_view.textDirection = View.TEXT_DIRECTION_LTR

设置 Textview 的 textDirection 的文字布局方向,强制 rtl 即可解决。