【问题标题】:How to add red wavy line below text in Android's TextView如何在 Android 的 TextView 中的文本下方添加红色波浪线
【发布时间】:2014-12-03 08:51:21
【问题描述】:

我正在尝试在文本中的错误下方添加红色波浪线,例如:

不幸的是,我找不到合适的 *Span 类来包装错误文本。

我应该如何在 Android 中实现这样的功能?

【问题讨论】:

  • 到目前为止你有没有尝试过?
  • 好吧,我研究了现有的 Span 类,但没有找到符合要求的。我正在尝试找到解决方法,目前正在研究编写自定义 Span。但我想知道我是否遗漏了什么——我不知道的功能、开源实现,甚至是关于如何实现类似功能的适当教程。

标签: android spannablestring


【解决方案1】:

这是一个不涉及资源的解决方案:

public class WavyUnderlineSpan implements LineBackgroundSpan {

private int color;
private int lineWidth;
private int waveSize;

public WavyUnderlineSpan() {
    this(Color.RED, 1, 3);
}

public WavyUnderlineSpan(int color, int lineWidth, int waveSize) {
    this.color = color;
    this.lineWidth = lineWidth;
    this.waveSize = waveSize;
}

@Override
public void drawBackground(Canvas canvas, Paint paint, int left, int right, int top, int baseline, int bottom,
                           CharSequence text, int start, int end, int lnum) {
    Paint p = new Paint(paint);
    p.setColor(color);
    p.setStrokeWidth(lineWidth);

    int width = (int) paint.measureText(text, start, end);
    int doubleWaveSize = waveSize * 2;
    for (int i = left; i < left + width; i += doubleWaveSize) {
        canvas.drawLine(i, bottom, i + waveSize, bottom - waveSize, p);
        canvas.drawLine(i + waveSize, bottom - waveSize, i + doubleWaveSize, bottom, p);
    }
}

}

【讨论】:

  • 赞成,如果没有资源中的额外位图,肯定会更好。缺少的一件事(小)是使用与设备无关的像素,以便波浪线在所有分辨率下看起来都一样。
  • 错误,现在测试 - 波浪线跨越整个字符串,而不仅仅是“跨越”文本
【解决方案2】:

我通过实现自定义 Span 解决了这个问题:

error_underline.png 添加到您的资源中:

然后使用这个类来创建跨度:

static class ErrorSpan extends DynamicDrawableSpan {

    private BitmapDrawable mRedWavy;
    private int mWidth;
    private int mBmpHeight;

    ErrorSpan(Resources resources) {
        super(DynamicDrawableSpan.ALIGN_BASELINE);
        mRedWavy = new BitmapDrawable(resources, BitmapFactory.decodeResource(resources, R.drawable.error_underline));
        mBmpHeight = mRedWavy.getIntrinsicHeight();
        mRedWavy.setTileModeX(TileMode.REPEAT);
    }

    @Override
    public Drawable getDrawable() {
        return mRedWavy;
    }

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


    @Override
    public void draw(Canvas canvas, CharSequence text,
                     int start, int end, float x, 
                     int top, int y, int bottom, Paint paint) {

        mRedWavy.setBounds(0, 0, mWidth, mBmpHeight);
        canvas.save();
        canvas.translate(x, bottom-mBmpHeight);
        mRedWavy.draw(canvas);
        canvas.restore();
        canvas.drawText(text.subSequence(start, end).toString(), x, y, paint);
    }
}

【讨论】:

  • 有没有办法用这种方法以编程方式改变颜色?如果您希望颜色为蓝色怎么办?
【解决方案3】:

@bpronin 的代码对我不起作用 - 跨度在高分辨率屏幕上太小,它跨越了整个文本,而不仅仅是跨越了错误。

但按照他的想法,我更新了我的答案以消除对添加资源的需求:

public class ErrorSpan extends DynamicDrawableSpan {

    private int width;
    int lineWidth;
    int waveSize;
    int color;


    public ErrorSpan(Resources resources) {
        this(resources, Color.RED, 1, 3);
    }

    public ErrorSpan(Resources resources, int color, int lineWidth, int waveSize) {
        super(DynamicDrawableSpan.ALIGN_BASELINE);
        // Get the screen's density scale
        final float scale = resources.getDisplayMetrics().density;
        // Convert the dps to pixels, based on density scale
        this.lineWidth = (int) (lineWidth * scale + 0.5f);
        this.waveSize = (int) (waveSize * scale + 0.5f);
        this.color = color;
    }

    @Override
    public Drawable getDrawable() {
        return null;
    }

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


    @Override
    public void draw(Canvas canvas, CharSequence text,
                     int start, int end, float x, 
                     int top, int y, int bottom, Paint paint) {

        Paint p = new Paint(paint);
        p.setColor(color);
        p.setStrokeWidth(lineWidth);

        int doubleWaveSize = waveSize * 2;
        for (int i = (int)x; i < x + width; i += doubleWaveSize) {
            canvas.drawLine(i, bottom, i + waveSize, bottom - waveSize, p);
            canvas.drawLine(i + waveSize, bottom - waveSize, i + doubleWaveSize, bottom, p);
        }
        canvas.drawText(text.subSequence(start, end).toString(), x, y, paint);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-22
    • 1970-01-01
    • 2016-05-22
    • 2021-10-05
    • 2022-06-17
    • 2017-03-25
    • 2011-03-15
    相关资源
    最近更新 更多