J'ai la chaîne suivante RM123.456. J'aimerais
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 à
Cependant, il est aligné vers le bas. Il ne s'aligne pas vers le haut.
J'essaie d'utiliser SuperscriptSpan
. Ça ressemble à
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.
Veuillez noter que nous ne souhaitons pas utiliser la solution 2 TextViews.
Cependant j'ai fait de cette façon:
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.
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.
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;
}
}
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:
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
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 ... )
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"));
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);
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
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)
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);