[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 即可解决。