How to add red wavy line under text in Android TextView

I am trying to add a red wavy line below the errors in the texts, for example:

enter image description here

Unfortunately, I cannot find a suitable * Span class to wrap error text.

How do I implement such a function in Android?

+3
source share
3 answers

The @bpronin code didn’t work for me - the range was too small on the high-resolution screen, and it covered all the text, and not only covered the error.

But after his idea, I updated my answer to remove the need to add a resource:

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

I solved the problem by running a custom Span:

Add error_underline.png to your resources: red wavy line <- tiny 6x3 pixels here

Then use this class to create intervals:

 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
source

Here is another solution without touching resources:

 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
source

Source: https://habr.com/ru/post/1483083/


All Articles