ForegroundColorSpan未应用于ReplacementSpan。

7

我正在尝试使用ReplacementSpans来格式化EditText字段中的输入(而无需修改内容):

public class SpacerSpan extends ReplacementSpan {
    @Override
    public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
        return (int) paint.measureText(text.subSequence(start,end)+" ");
    }
    @Override
    public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
        canvas.drawText(text.subSequence(start,end)+" ", 0, 2, x, y, paint);
    }
}

这样做能按预期工作并在跨越的部分之后添加间距。但是,如果我同时应用ForegroundColorSpan,则所跨越部分的颜色不会被设置:

EditText edit = (EditText) findViewById(R.id.edit_text);

SpannableString content = new SpannableString("1234567890");

ForegroundColorSpan fontColor = new ForegroundColorSpan(Color.GREEN);
SpacerSpan spacer = new SpacerSpan();
content.setSpan(fontColor, 0, content.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
content.setSpan(spacer, 4, 5, Spanned.SPAN_MARK_MARK);

edit.setText(content);

结果看起来像 http://i.cubeupload.com/4Us5Zj.png 如果我应用一个AbsoluteSizeSpan,指定的字体大小也会应用于替换Span部分。这是预期行为吗?我有什么遗漏的吗?还是Android中的一个错误?

由于SDK中ReplacementSpan的唯一具体实现是用图像替换文本,因此可能这些内容在用更多文本替换文本方面并没有得到很好的测试。ForegroundColorSpanAbsoluteSizeSpan之间的一个区别是后者覆盖了updateMeasureState()updateDrawState(),而ForegroundColorSpan仅覆盖了updateDrawState()。这是有道理的,因为前景色不会影响测量。但是,传递给draw()Paint可能是错误的。 - CommonsWare
是的,似乎传递给draw()Paint不同(如果我记录设置的paint,则输出为): ForegroundColor. r: 0, g: 255, b: 0 Color during draw. r: 0, g: 0, b: 0 - Andreas Wenger
作为测试,你可以尝试创建ForegroundColorSpan的子类,并覆盖updateMeasureState()以执行updateDrawState()所做的操作,然后尝试应用你的子类代替ForegroundColorSpan。如果你的子类有效,那么好消息是你将确切知道问题的根源。坏消息是,如果Spanned通过Bundle传递,只有内置的ParcelableSpans受支持,你可能会失去你的子类。 - CommonsWare
1个回答

6
CommonWare指引我走向了正确的方向。似乎在任何CharacterStyleSpan被查询之前,ReplacementSpans被呈现[1]。
一种可能的(但丑陋的)解决方法是实现一个自定义的ForegroundColorSpan,它扩展了MetricAffectingSpan(在绘制ReplacementSpans之前会查询MetricAffectingSpans [1])。
public class FontColorSpan extends MetricAffectingSpan {

    private int mColor;

    public FontColorSpan(int color) {
        mColor = color;
    }

    @Override
    public void updateMeasureState(TextPaint textPaint) {
        textPaint.setColor(mColor);
    }
    @Override
    public void updateDrawState(TextPaint textPaint) {
        textPaint.setColor(mColor);
    }
} 

我猜这是一个应该报告的错误?

[1]http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.0.2_r1/android/text/TextLine.java#936


1
这也解释了为什么应用了AbsoluteSizeSpan(它扩展了MetricAffectingSpan)。 - Andreas Wenger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接