在自定义 android 视图中,我正在绘制几个可能是双向的用户输入文本。例如希伯来语或阿拉伯语与英语文本或数字混合。为了绘制文本,我基本上使用视图的 Canvas、TextPaint 和 StaticLayout。实际的代码相当复杂且分散,但绘制文本的部分如下所示:
TextPaint _paint = getPaint();
Canvas _canvas = ...; // the canvas passed in the View.onDraw(Canvas canvas) method
PointF l = locationCenter(); // the location at which the center of text should be painted
int alignment = getAlignment(); // for this element, can vary for each element.
PointF textSize = getTextBounds(); // the bounding box of the text
String text = userInputText(); // actually some user input BiDi text
switch (alignment) {
case 0:
_paint.setTextAlign(Paint.Align.CENTER);
l.x += textSize.x / 2.0f;
break;
case 1:
_paint.setTextAlign(Paint.Align.LEFT);
l.x -= 1;
break;
default:
_paint.setTextAlign(Paint.Align.RIGHT);
l.x += (textSize.x + 1);
break;
}
StaticLayout layout = new StaticLayout(text, _paint, (int) Math.ceil(textSize.x + 0.5f), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
_canvas.translate(l.x, l.y);
layout.draw(_canvas);
_canvas.translate(-l.x, -l.y);
这适用于仅 LTR 或 RTL 文本,但不适用于出现乱码的 Bidi 文本。奇怪的是,当我强制对齐为 0 时(导致 _paint.setTextAlign(Paint.Align.Left) 它通常看起来工作正常(=据我测试)。但是,当文本包含时,使对齐条件为 0 BiDi(或 RTL)字符,不起作用。似乎 Canvas、Paint 或 StaticLayout 都在保留状态。
我尝试像这样使用 BidiFormatter:
BidiFormatter.Builder builder = new BidiFormatter.Builder();
builder.stereoReset(true);
android.support.v4.text.BidiFormatter formatter = builder.build();
String text = formatter.unicodeWrap(userInputText());
// proceed as above
但这没有区别(仍然是乱码)。
知道如何在自定义视图中可靠地绘制(许多)双向文本吗?并且任何想法为什么强制所有文本对齐到 Paint.Align.Left似乎可以解决问题。这应该最好从 android 4.0 开始工作,但至少 4.2 或 4.4。提前致谢。
我通过使用 Character.getDirectionality 来测试文本中的 rtl 字符或多或少地工作:
public static boolean containsRtlChar(String text) {
for (int i = 0; i < text.length(); i++) {
int c = text.codePointAt(i);
int direction = Character.getDirectionality(c);
if ((direction == Character.DIRECTIONALITY_RIGHT_TO_LEFT) || (direction == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC) || (direction == Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING) || (direction == Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE))
return true;
}
return false;
}
然后基于该力对齐到左(
if (containsRtlChars(text)) {
alignment = TextStyle.textAlignLeft;
}
这会导致包含 RTL 字符的文本正常,尽管具有固定(中心)对齐。