Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
392 views
in Technique[技术] by (71.8m points)

android - How to create vertically aligned superscript and subscript in TextView

In the example of image below:

enter image description here

How can I make both the superscript and subscript numbers to be aligned to produce a common scientific notation like below

enter image description here

in TextView? If there is a way using Spannable or ReplacementSpan I would like to see a working example. Thank you.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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:

Sample

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...