6

我想要在 IDE 中看起来像错误的 Spannable - 用另一种颜色下划线。

我尝试创建ColorUnderlineSpan扩展 android 的类UnderlineSpan,但它使所有文本成为另一种颜色(我只需要添加彩色下划线):

/**
 * Underline Span with color
 */
public class ColorUnderlineSpan extends android.text.style.UnderlineSpan {

    private int underlineColor;

    public ColorUnderlineSpan(int underlineColor) {
        super();
        this.underlineColor = underlineColor;
    }

    @Override
    public void updateDrawState(TextPaint ds) {
        super.updateDrawState(ds);
        ds.setColor(underlineColor);
    }
}

我也找到了DynamicDrawableSpan课程,但我看不到要绘制的画布边界。

使用带有边界参数的抽象绘制方法获得任何 Spannable 实现会很棒。

4

2 回答 2

9

这不是最漂亮的解决方案,但它最终对我有用:

public class CustomUnderlineSpan implements LineBackgroundSpan {

int color;
Paint p;
int start, end;
public CustomUnderlineSpan(int underlineColor, int underlineStart, int underlineEnd) {
    super();
    color = underlineColor;
    this.start = underlineStart;
    this.end = underlineEnd;
    p = new Paint();
    p.setColor(color);
    p.setStrokeWidth(3F);
    p.setStyle(Paint.Style.FILL_AND_STROKE);
}

@Override
public void drawBackground(Canvas c, Paint p, int left, int right, int top, int baseline, int bottom, CharSequence text, int start, int end, int lnum) {

    if (this.end < start) return;
    if (this.start > end) return;

    int offsetX = 0;
    if (this.start > start) {
        offsetX = (int)p.measureText(text.subSequence(start, this.start).toString());
    }

    int length = (int)p.measureText(text.subSequence(Math.max(start, this.start), Math.min(end, this.end)).toString());
    c.drawLine(offsetX, baseline + 3F, length + offsetX, baseline + 3F, this.p);
}

这很奇怪,因为你必须指定字符索引来开始和结束你的下划线,但它对我有用。

于 2014-01-13T17:31:58.690 回答
4

@korbonix 发布的答案效果很好。我在 Kotlin 中做了一些改进并支持多行 TextView:

class ColorUnderlineSpan(val underlineColor: Int, val underlineStart: Int, val underlineEnd: Int): LineBackgroundSpan {

    val paint = Paint()

    init {
        paint.color = underlineColor
        paint.strokeWidth = 3.0f
        paint.style = Paint.Style.FILL_AND_STROKE
    }

    override fun drawBackground(c: Canvas?, p: Paint?, left: Int, right: Int, top: Int, baseline: Int, bottom: Int, text: CharSequence?, start: Int, end: Int, lnum: Int) {
        if (!(underlineStart < underlineEnd)) {
            throw Error("underlineEnd should be greater than underlineStart")
        }

        if (underlineStart > end || underlineEnd < start) {
            return
        }

        var offsetX = 0

        if (underlineStart > start) {
            offsetX = p?.measureText(text?.subSequence(start, underlineStart).toString())?.toInt() ?: 0
        }

        val length: Int = p?.measureText(text?.subSequence(Math.max(start, underlineStart), Math.min(end, underlineEnd)).toString())?.toInt()
            ?: 0

        c?.drawLine(offsetX.toFloat(), baseline + 3.0f, (length + offsetX).toFloat(), baseline + 3.0f, paint)
    }
}

这是一个示例用法。textText 是文本视图。文本长度为 127 个字符,下划线从位置 112 到 127。

重要提示:由于我不完全理解的原因,跨度长度应设置为文本的全长。否则该组件甚至不会被调用。随时教育我为什么会这样。

    // Sets link color
    val spannable = SpannableString(getString(R.string.forgot_text))
    spannable.setSpan(
            ColorUnderlineSpan(Color.RED), 112, 127),
            0, 127, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
    textText.text = spannable
于 2018-11-26T13:28:21.763 回答