How to make RelativeSizeSpan align to top

后端 未结 9 2003
情深已故
情深已故 2021-01-31 03:14

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

  • Make RM relatively smaller
  • Make RM aligned to to
相关标签:
9条回答
  • 2021-01-31 03:24

    you have to used html tag like below for subscript and superscript.It works like charm.

     ((TextView) findViewById(R.id.text)).setText(Html.fromHtml("<sup><small>2</small></sup>X"));
    

    or

    You can also use below code:

    String titleFirst = "Insert GoTechTM device into the vehicle\'s OBDII port.";
    SpannableStringBuilder cs = new SpannableStringBuilder(titleFirst);
    cs.setSpan(new SuperscriptSpan(), titleFirst.indexOf("TM"), titleFirst.indexOf("TM")+2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    cs.setSpan(new RelativeSizeSpan((float)0.50), titleFirst.indexOf("TM"), titleFirst.indexOf("TM")+2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);        
    txtPairInstructionFirst.setText(cs);
    
    0 讨论(0)
  • 2021-01-31 03:28

    Many of the provided answers here require you to set a text size scale percentage and guess an offset to account for their mistake in calculating the correct offset or they require you to set multiple spans.

    So, to update this question, here's a solution which sets the correct baseline of the superscript and only asks that you provide a text scale percentage for only 1 required span:

    class TopAlignSuperscriptSpan(private val textSizeScalePercentage: Float = 0.5f) : MetricAffectingSpan() {
    
        override fun updateDrawState(tp: TextPaint) {
            tp.baselineShift += (tp.ascent() * textSizeScalePercentage).toInt()
            tp.textSize = tp.textSize * textSizeScalePercentage
        }
    
        override fun updateMeasureState(tp: TextPaint) {
            updateDrawState(tp)
        }
    }
    

    You may use this without having to set other spans, like so:

    val spannableString = SpannableString("RM123.456")
    spannableString.setSpan(TopAlignSuperscriptSpan(0.6f), 0, 2, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE)
    myTextView.text = spannableString
    

    "RM" will be 60% of the text size of "123.456" and it's top will be exactly aligned to the top of "123.456"

    UPDATE: You shouldn't use this because it is inexact, like every other answer here. Instead, I would suggest calculating the height of each section of the text view and manually setting the y value of each section, like this library does: https://github.com/fabiomsr/MoneyTextView/tree/master/moneytextview/src/main/res/values

    0 讨论(0)
  • 2021-01-31 03:29

    I had a look at the RelativeSizeSpan and found a rather simple implementation. So you could just implement your own RelativeSizeSpan for your purpose. The only difference here is that it doesn't implement ParcelableSpan, since this is only intended for framework code. AntiRelativeSizeSpan is just a fast hack without much testing of course, but it seems to work fine. It completely relies on Paint.getTextBounds() to find the best value for the baselineShift, but maybe there'd be a better approach.

    public class AntiRelativeSizeSpan extends MetricAffectingSpan {
        private final float mProportion;
    
        public AntiRelativeSizeSpan(float proportion) {
            mProportion = proportion;
        }
    
        public float getSizeChange() {
            return mProportion;
        }
    
        @Override
        public void updateDrawState(TextPaint ds) {
            updateAnyState(ds);
        }
    
        @Override
        public void updateMeasureState(TextPaint ds) {
            updateAnyState(ds);
        }
    
        private void updateAnyState(TextPaint ds) {
            Rect bounds = new Rect();
            ds.getTextBounds("1A", 0, 2, bounds);
            int shift = bounds.top - bounds.bottom;
            ds.setTextSize(ds.getTextSize() * mProportion);
            ds.getTextBounds("1A", 0, 2, bounds);
            shift += bounds.bottom - bounds.top;
            ds.baselineShift += shift;
        }
    }
    
    0 讨论(0)
  • 2021-01-31 03:31

    You could achieve top gravity by creating a custom MetricAffectingSpan class

    here is the code of custom class:

    public class CustomCharacterSpan extends MetricAffectingSpan {
        double ratio = 0.5;
    
        public CustomCharacterSpan() {
        }
    
        public CustomCharacterSpan(double ratio) {
            this.ratio = ratio;
        }
    
        @Override
        public void updateDrawState(TextPaint paint) {
            paint.baselineShift += (int) (paint.ascent() * ratio);
        }
    
        @Override
        public void updateMeasureState(TextPaint paint) {
            paint.baselineShift += (int) (paint.ascent() * ratio);
        }
    }
    

    Applying the span:

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

    Output:

    For more info on MetricAffectingSpan : http://developer.android.com/reference/android/text/style/MetricAffectingSpan.html

    Custom MetricAffectingSpan logic referred from : Two different styles in a single textview with different gravity and hieght

    0 讨论(0)
  • 2021-01-31 03:32

    I have implemented this in one of my application.

     <TextView
        android:id="@+id/txt_formatted_value"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:textColor="#000000"       
        android:textSize="28dp" />
    

    In Activity/Frgament.class

     myTextView = (TextView) view.findViewById(R.id.txt_formatted_value);
    

    Hardcoded for testing purpose,

    String numberValue = "123.456";    
    myTextView.setText(UtilityClass.getFormattedSpannedString("RM"+numberValue,
         numberValue.length(),0));
    

    Add this class in your package,

    public class SuperscriptSpanAdjuster extends MetricAffectingSpan {
    double ratio = 0.5;
    
    public SuperscriptSpanAdjuster() {
    }
    
    public SuperscriptSpanAdjuster(double ratio) {
        this.ratio = ratio;
    }
    
    @Override
    public void updateDrawState(TextPaint paint) {
        paint.baselineShift += (int) (paint.ascent() * ratio);
    }
    
    @Override
    public void updateMeasureState(TextPaint paint) {
        paint.baselineShift += (int) (paint.ascent() * ratio);
    }
    

    }

    Created the format method in UntilityClass.class

     public static SpannableString getFormattedSpannedString(String value, int mostSignificantLength, int leastSignificantLength){
    
        SpannableString  spanString = new SpannableString(value);
        /* To show the text in top aligned(Normal)*/
        spanString.setSpan(new SuperscriptSpanAdjuster(0.7), 0,spanString.length()-mostSignificantLength-leastSignificantLength, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
        /* Show the number of characters is normal size (Normal)*/
        spanString.setSpan(new RelativeSizeSpan(1.3f), 0,spanString.length()-mostSignificantLength-leastSignificantLength, 0);
        /*To set the text style as bold(MostSignificant)*/
        //spanString.setSpan(new StyleSpan(Typeface.BOLD), spanString.length()-mostSignificantLength-leastSignificantLength, spanString.length()-leastSignificantLength, 0);
        /*To set the text color as WHITE(MostSignificant)*/
        //spanString.setSpan(new ForegroundColorSpan(Color.WHITE), spanString.length()-mostSignificantLength-leastSignificantLength,  spanString.length()-leastSignificantLength, 0);
        /*Show the number of characters as most significant value(MostSignificant)*/
        spanString.setSpan(new RelativeSizeSpan(2.3f), spanString.length()-mostSignificantLength-leastSignificantLength, spanString.length()-leastSignificantLength, 0);
    
        /* To show the text in top aligned(LestSignificant)*/
        spanString.setSpan(new SuperscriptSpanAdjuster(1.2), spanString.length()-leastSignificantLength, spanString.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
        /*To set the text style as bold(LestSignificant)*/
        //spanString.setSpan(new StyleSpan(Typeface.BOLD), spanString.length()-leastSignificantLength, spanString.length(), 0);
        /*Show the number of characters as most significant value(LestSignificant)*/
        spanString.setSpan(new RelativeSizeSpan(0.8f), spanString.length()-leastSignificantLength, spanString.length(), 0);
    
        return spanString;
    }
    

    Using this method you can do more circus like changing text style, color separately for SuperScript. Also you can add superscript both right and left side.(Here I commented all the code, if you want can give a try...)

    0 讨论(0)
  • 2021-01-31 03:36

    However I did in this way:

    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.

    0 讨论(0)
提交回复
热议问题