How to create vertically aligned superscript and subscript in TextView

android, subscript, superscript, textview

Solution

You might want to try something like this.

It's basicall a `ReplacementSpan` that takes the text it's applied on, separates it into two parts, and draws them on the canvas. The size factor and y translation are somewhat hand-picked. I hope it's useful (or at least that you or someone else can build on it).

public class SuperSubSpan extends ReplacementSpan
{
    @Override
    public int getSize(Paint paint, CharSequence text, int start, int end, FontMetricsInt fm)
    {
        text = text.subSequence(start, end);
        String[] parts = text.toString().split(",");

        Paint p = getSuperSubPaint(paint);
        return (int) Math.max(p.measureText(parts[0]), p.measureText(parts[1]));
    }

    private static TextPaint getSuperSubPaint(Paint src)
    {
        TextPaint paint = new TextPaint(src);
        paint.setTextSize(src.getTextSize() / 2.5f);
        return paint;
    }

    @Override
    public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint)
    {
        text = text.subSequence(start, end);
        String[] parts = text.toString().split(",");

        Paint p = getSuperSubPaint(paint);

        float width1 = p.measureText(parts[0]);
        float width2 = p.measureText(parts[1]);
        float maxWidth = Math.max(width1, width2);

        canvas.drawText(parts[0], x + (maxWidth - width1), y - (bottom - top) / 3f, p);
        canvas.drawText(parts[1], x + (maxWidth - width2), y + (bottom - top) / 10f, p);
    }
}

Then use it as:

Spannable str = new SpannableString("9,4Be -> 2000,127Jo");
str.setSpan(new SuperSubSpan(), 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
str.setSpan(new SuperSubSpan(), 9, 17, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
mTextView.setText(str);

which produces the following result:

A slightly better solution would be to have a special format for these strings (e.g. `"{9,4}Be -> {2000,127}Jo"`) and have a regular expression process the string and add the corresponding `SuperSubSpans`, just so that you don't need to this manually. But the actual Span part would be more or less the same.

Problem

In the example of image below: How can I make both the superscript and subscript numbers to be aligned to produce a common scientific notation like below in `TextView`? If there is a way using `Spannable` or `ReplacementSpan` I would like to see a working example. Thank you.

Original source

Related problems