How to make RelativeSizeSpan align to top

Cheok Yan Cheng picture Cheok Yan Cheng · May 1, 2016 · Viewed 7k times · Source

I have the following String RM123.456. I would like to

  • Make RM relatively smaller
  • Make RM aligned to top exactly

I almost able to achieve it by using

spannableString.setSpan(new RelativeSizeSpan(0.50f), 0, index, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(spannableString, TextView.BufferType.SPANNABLE);

The outcome looks like

enter image description here

However, it is aligned to the bottom. It doesn't align to the top.

I try to use SuperscriptSpan. It looks like

enter image description here

It doesn't do what I want as

  • SuperscriptSpan doesn't make the text smaller. I'm not able to control its sizing.
  • SuperscriptSpan will make the text "over the top align"

May I know, how can I make RelativeSizeSpan align to top exactly?

This is what I wish to achieve.

enter image description here

Please note, we don't wish to go for 2 TextViews solution.

Answer

Hiren Patel picture Hiren Patel · May 4, 2016

However I did in this way:

enter image description here

activity_main.xml:

<TextView
    android:id="@+id/txtView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="50dp"
    android:textSize="26sp" />

MainActivity.java:

TextView txtView = (TextView) findViewById(R.id.txtView);

SpannableString spannableString = new SpannableString("RM123.456");
spannableString.setSpan( new TopAlignSuperscriptSpan( (float)0.35 ), 0, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE );
txtView.setText(spannableString);

TopAlignSuperscriptSpan.java:

private class TopAlignSuperscriptSpan extends SuperscriptSpan {
        //divide superscript by this number
        protected int fontScale = 2;

        //shift value, 0 to 1.0
        protected float shiftPercentage = 0;

        //doesn't shift
        TopAlignSuperscriptSpan() {}

        //sets the shift percentage
        TopAlignSuperscriptSpan( float shiftPercentage ) {
            if( shiftPercentage > 0.0 && shiftPercentage < 1.0 )
                this.shiftPercentage = shiftPercentage;
        }

        @Override
        public void updateDrawState( TextPaint tp ) {
            //original ascent
            float ascent = tp.ascent();

            //scale down the font
            tp.setTextSize( tp.getTextSize() / fontScale );

            //get the new font ascent
            float newAscent = tp.getFontMetrics().ascent;

            //move baseline to top of old font, then move down size of new font
            //adjust for errors with shift percentage
            tp.baselineShift += ( ascent - ascent * shiftPercentage )
                    - (newAscent - newAscent * shiftPercentage );
        }

        @Override
        public void updateMeasureState( TextPaint tp ) {
            updateDrawState( tp );
        }
    }

Hope this will help you.