web-dev-qa-db-fra.com

Comment aligner RelativeSizeSpan vers le haut

J'ai la chaîne suivante RM123.456. J'aimerais

  • Rendre RM relativement plus petit
  • Faites en sorte que RM soit aligné exactement au dessus

J'ai presque réussi à le réaliser en utilisant

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

Le résultat ressemble à

 enter image description here

Cependant, il est aligné vers le bas. Il ne s'aligne pas vers le haut. 

J'essaie d'utiliser SuperscriptSpan. Ça ressemble à

 enter image description here

Il ne fait pas ce que je veux

  • SuperscriptSpan ne réduit pas le texte. Je ne suis pas capable de contrôler son dimensionnement.
  • SuperscriptSpan alignera le texte "sur le dessus"

Puis-je savoir, comment puis-je aligner RelativeSizeSpan au sommet exactement?

C'est ce que je souhaite réaliser.

 enter image description here

Veuillez noter que nous ne souhaitons pas utiliser la solution 2 TextViews.

32
Cheok Yan Cheng

Cependant j'ai fait de cette façon:

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

J'espère que ceci vous aidera.

19
Hiren Patel

J'ai jeté un oeil à la RelativeSizeSpan et trouvé une implémentation plutôt simple. Donc, vous pouvez simplement mettre en œuvre votre propre RelativeSizeSpan pour vos besoins. La seule différence est qu’il n’implémente pas ParcelableSpan, car il s’agit uniquement de code framework. AntiRelativeSizeSpan est juste un hack rapide sans beaucoup de tests bien sûr, mais cela semble bien fonctionner. Il repose entièrement sur Paint.getTextBounds() pour trouver le meilleur rapport qualité/prix pour la baselineShift, mais il y aurait peut-être une meilleure approche.

 Original RelativeSizeSpan  AntiRelativeSizeSpan

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;
    }
}
12
tynn

Vous pouvez atteindre le sommet de la gravité en créant une classe MetricAffectingSpan personnalisée.

voici le code de la classe personnalisée:

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

Application du 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);

Sortie:

 enter image description here

Pour plus d'informations sur MetricAffectingSpan: http://developer.Android.com/reference/Android/text/style/MetricAffectingSpan.html

Logique MetricAffectingSpan personnalisée faisant référence à partir de: Deux styles différents dans une même vue texte avec une gravité et une hauteur différentes

10
Abhishek V

J'ai implémenté cela dans l'une de mes applications.

 <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" />

En activité/classe.classe

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

Codé en dur à des fins de test,

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

Ajouter cette classe dans votre paquet,

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

}

Création de la méthode de formatage dans 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;
}

En utilisant cette méthode, vous pouvez faire plus de cirque, comme changer le style du texte, colorer séparément pour SuperScript . Vous pouvez également ajouter un exposant à la fois du côté droit et du côté gauche. (Ici, j'ai commenté tout le code, si vous le souhaitez ... )

 enter image description here  enter image description here  enter image description here

8
Srinivasan

vous devez utiliser les balises html comme ci-dessous pour indice et exposant.

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

 enter image description here

ou

Vous pouvez également utiliser le code ci-dessous:

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);
6
Darshan Mistry

La plupart des réponses fournies ici nécessitent que vous définissiez un pourcentage d'échelle de la taille du texte et que vous deviniez un décalage pour tenir compte de leur erreur lors du calcul du décalage correct, ou vous demandiez de définir plusieurs étendues.

Donc, pour mettre à jour cette question, voici une solution qui définit la ligne de base correcte de l'indice et ne demande que vous fournissiez un pourcentage d'échelle de texte pour 1 seule plage requise:

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

Vous pouvez l'utiliser sans avoir à définir d'autres portées, comme ceci:

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

"RM" correspondra à 60% de la taille du texte de "123.456" et sa partie supérieure sera exactement alignée sur celle de "123.456"

UPDATE: vous ne devriez pas utiliser ceci car il est inexact, comme pour toute autre réponse ici . Au lieu de cela, je suggérerais de calculer la hauteur de chaque section de la vue texte et de définir manuellement la valeur y de chaque section, comme le fait cette bibliothèque: https://github.com/fabiomsr/MoneyTextView/tree/master/moneytextview/src/main/res/values ​​

0
w3bshark

Je sais que c’est un vieux fil, mais j’en suis tombé aujourd’hui, et je suis étonné que personne ne réponde à cela… Je recommanderais de ne pas coder en dur le 2, 4 

val span = SpannableStringBuilder.valueOf("$temp")
span.append("°F", SuperscriptSpan(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
span.setSpan(RelativeSizeSpan(0.5f), 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
tempTextView.setText(span, TextView.BufferType.SPANNABLE)
0
Joshua King

Classe pour top align qui doit être utilisé à la place de RelativeSizeSpan (non complémentaire):

import Android.text.TextPaint;
import Android.text.style.MetricAffectingSpan;

public class TopRelativeSizeSpan extends MetricAffectingSpan {

    private final float mProportion;

    public TopRelativeSizeSpan(float proportion) {
        mProportion = proportion;
    }

    @Override
    public void updateDrawState(TextPaint ds) {
        ds.baselineShift += (mProportion - 1) * (ds.getTextSize() - ds.descent());
        ds.setTextSize(ds.getTextSize() * mProportion);
    }

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

Et utilisation:

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