Android 替换span';s draw()方法是';我没打电话

Android 替换span';s draw()方法是';我没打电话,android,spannablestring,Android,Spannablestring,我用字符串设置背景,如下所示: spanString.setSpan(new BackgroundColorSpan(color), 0, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 但我想在这个背景中增加左和右填充,所以我创建了自定义跨度 public class PaddingBackgroundSpan extends ReplacementSpan { private int mBackgroundColor; private int mForegrou

我用字符串设置背景,如下所示:

spanString.setSpan(new BackgroundColorSpan(color), 0, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
但我想在这个背景中增加左和右填充,所以我创建了自定义跨度

public class PaddingBackgroundSpan extends ReplacementSpan {
private int mBackgroundColor;
private int mForegroundColor;

public PaddingBackgroundSpan(int backgroundColor, int foregroundColor) {
    this.mBackgroundColor = backgroundColor;
    this.mForegroundColor = foregroundColor;
}

@Override
public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
    return Math.round(measureText(paint, text, start, end));

}

@Override
public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
    RectF rect = new RectF(x, top, x + measureText(paint, text, start, end), bottom);
    paint.setColor(mBackgroundColor);
    canvas.drawRect(rect, paint);
    paint.setColor(mForegroundColor);
    canvas.drawText(text, start, end, x, y, paint);
}

private float measureText(Paint paint, CharSequence text, int start, int end) {
    return paint.measureText(text, start, end);
}
我通过以下方式使用我的跨度:

spanString.setSpan(new PaddingBackgroundSpan(color1, color2), 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

不幸的是,没有调用我的draw()方法。getSize()调用正确。

调用该视图的
invalidate()
方法,以便强制调用
draw()
如果有人遇到此问题,我会遇到它。我要做的是将第二个参数传递到setText()方法中。我的电话看起来像

textView.setText(spanned, TextView.BufferType.SPANNABLE);

希望这有帮助

看来我找到了一个解决这个问题的有效(但不太可靠)方法。尝试在字符串的末尾添加另一个符号,使其不包含在span中,然后调用
draw()

 char EXTRA_SPACE = ' ';
 String text = originalString + EXTRA_SPACE;
 Spannable spannable = new SpannableString(text);
 spannable.setSpan(new MyReplacementSpan(), 0, text.length()-1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
 textView.setText(spannable);

看起来它忽略了整个字符串宽度的跨距。

即使返回跨距的宽度,当跨距覆盖整个字符串时,跨距的高度也为0。因此,跨度实际上在那里,具有指定的宽度,但高度为0,因此未绘制

您必须设置跨度的高度,以更新函数getSize的参数Paint.FontMetricsInt fm的值。检查函数作为参考,通过更新FontMetrics值来设置高度。

在方法
getSize()
中,必须根据
Paint
FontMetricsInt重新计算
Paint.FontMetricsInt fm

@Override
public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
    width = Math.round(paint.measureText(text, start, end));
    Paint.FontMetricsInt metrics = paint.getFontMetricsInt();
    if (fm != null) {
        fm.top = metrics.top;
        fm.ascent = metrics.ascent;
        fm.descent = metrics.descent;

        fm.bottom = metrics.bottom;
    }
    return width;
}

我想这对你有帮助。设置文本视图宽度与父级匹配。 main_activity.xml

<TextView
   android:width="match_parent"
的文档提供了以下答案:

返回跨度的宽度。扩展类可以通过更新Paint.FontMetricsInt的属性来设置跨度的高度如果span覆盖整个文本,并且未设置高度,则span将不会调用draw()

确保使用正确的值更新
Paint.FontMetricsInt
,以解决问题

在我的例子中,我只是从
TextView
Paint
中获取指标:

@覆盖
公共整数getSize(
油漆,
字符序列文本,
int start,
int end,
Paint.FontMetricsInt格式){
final Paint.FontMetrics paintFontMetrics=Paint.getFontMetrics();
如果(fm!=null){
fm.ascent=(int)paintFontMetrics.ascent;
fm.bottom=(int)paintFontMetrics.bottom;
fm.descent=(int)paintFontMetrics.descent;
fm.leading=(int)paintFontMetrics.leading;
fm.top=(int)paintFontMetrics.top;
}
//...
}

我不想在视图级别上搞得一团糟,我希望Span能够像标准背景色Span那样自行填充。可能吗?我刚刚检查了你的解决方案。在添加SpannableString后调用TextView上的invalidate(这是您的建议吗?),但它不起作用。的确,它起作用了,但为什么我们需要这样的解决方法呢。。