ReplacementSpan's draw() method isn't called

萝らか妹 提交于 2019-12-03 16:56:34

问题


I set background in string like that:

spanString.setSpan(new BackgroundColorSpan(color), 0, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

But I would like to increase left and right padding in this background so I created custom span

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);
}

I use my span by:

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

Unfortunately, my draw() method isn't called. getSize() is called correctly.


回答1:


In case anyone has this problem, I encountered it. What I had to do is to pass a second parameter into the setText() method. My call looked like

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

Hope this helps!




回答2:


In method getSize() the Paint.FontMetricsInt fm must be recalculated based on paint FontMetricsInt:

@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;
}



回答3:


Looks like I found a working (but hacky) solution to this problem. Try to add another symbol to the end of the string so that it isn't included in the span - and then draw() gets called!

 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);

Looks like it ignores the spans which are whole string wide.




回答4:


Even if you return the width of the span, the height of the span is 0 when the span covers the whole string. Therefore your span is actually there, with the specified width but the height is 0, therefore not drawn.

You have to set the height of the span updating the values of the parameter Paint.FontMetricsInt fm for function getSize. Check the DynamicDrawable.getSize function as a reference to set the height by updating the FontMetrics values.




回答5:


The documentation for ReplacementSpan.getSize() provides the answer:

Returns the width of the span. Extending classes can set the height of the span by updating attributes of Paint.FontMetricsInt. If the span covers the whole text, and the height is not set, draw() will not be called for the span.

Make sure to update Paint.FontMetricsInt with proper values to fix the problem.

In my case, I just took the metrics from the TextView's Paint:

@Override
public int getSize(
        Paint paint,
        CharSequence text,
        int start,
        int end,
        Paint.FontMetricsInt fm) {
    final Paint.FontMetrics paintFontMetrics = paint.getFontMetrics();
    if (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;
    }
    //...
}



回答6:


Call that view's invalidate() method in order to force invoke on draw().




回答7:


I think it helps to you. Set textView width match parent. main_activity.xml

<TextView
   android:width="match_parent"


来源:https://stackoverflow.com/questions/20069537/replacementspans-draw-method-isnt-called

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!