I'm trying to add red wavy line below errors in texts, such as:
Unfortunately I can't find a proper *Span class to wrap the error text with.
How should I implement such a feature in Android?
This example demonstrates how do I add a line break in an android textView. Step 1 − Create a new project in Android Studio, go to File ⇒ New Project and fill all required details to create a new project. Step 2 − Add the following code to res/layout/activity_main.xml. Step 3 − Add the following code to src/MainActivity.java
Go to res > drawable > new > drawable resource file and create a new file and name it “ dashed_underline.xml ” and define all properties of the dashed line that we need. Later we will add this as the background of TextView. Below is the code for dashed_underline.xml comments is added for a better understanding of the code.
We will see the code for underline text in an Android layout using XML resource file and Programmatically code approach. Step 1. Create a new project “ Build Your First Android App in Kotlin “ Step 2. Add a string in the XML file and add the below code. File Location: res/values/strings.xml (open the file and new strings – “ul_string_here”.
If you are adding text to the Textview from Strings folder you can specify as follows.. From If You are Adding text dynamically in that case you use the following. Its works for me. Example using ConstraintLayout. Constrain the view to the TextView. A line with the exact space of the TextView will be drawn.
Here is a 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);
}
}
}
I've solved the problem by implementing a custom Span:
Add error_underline.png
to your resources: <-- tiny 6x3 pixels here
Then use this class to create spans:
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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With