Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add red wavy line below text in Android's TextView

I'm trying to add red wavy line below errors in texts, such as:

enter image description here

Unfortunately I can't find a proper *Span class to wrap the error text with.

How should I implement such a feature in Android?

like image 516
Iftah Avatar asked Dec 03 '14 08:12

Iftah


People also ask

How to add a line break in an Android textview?

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

How to add dashed underline to textview in Android?

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.

How to underline text in Android layout using Kotlin?

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”.

How to add text to textview from strings?

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.


2 Answers

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

}

like image 62
bpronin Avatar answered Sep 18 '22 22:09

bpronin


I've solved the problem by implementing a custom Span:

Add error_underline.png to your resources: red wavy line <-- 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);
    }
}
like image 43
Iftah Avatar answered Sep 18 '22 22:09

Iftah