Как сделать RelativeSizeSpan выровненным вверх
У меня есть следующая строка RM123.456. Я хотел бы
- Сделать RM относительно небольшим
- Сделайте RM выровненным вверх точно
Я почти достигал этого, используя
spannableString.setSpan(new RelativeSizeSpan(0.50f), 0, index, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(spannableString, TextView.BufferType.SPANNABLE);
Результат выглядит как
![введите описание изображения здесь]()
Однако он выровнен по отношению к нижней части. Он не соответствует вершине.
Я пытаюсь использовать SuperscriptSpan
. Он выглядит как
![введите описание изображения здесь]()
Он не делает то, что я хочу, как
-
SuperscriptSpan
не уменьшает текст. Я не могу контролировать его размер.
-
SuperscriptSpan
сделает текст "над верхним выравниванием"
Могу ли я узнать, как я могу установить RelativeSizeSpan в начало точно?
Это то, чего я хочу достичь.
![введите описание изображения здесь]()
Обратите внимание: мы не хотим идти на 2 решения TextViews.
Ответы
Ответ 1
Однако я сделал так:
![введите описание изображения здесь]()
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 );
}
}
Надеюсь, это поможет вам.
Ответ 2
Я посмотрел на RelativeSizeSpan
и нашел довольно простую реализацию. Поэтому вы можете просто реализовать свой собственный RelativeSizeSpan
для своей цели. Единственное отличие здесь в том, что он не реализует ParcelableSpan
, так как это предназначено только для кода рамки. AntiRelativeSizeSpan
- это просто быстрый взлом без особого тестирования, но, похоже, он работает нормально. Он полностью полагается на Paint.getTextBounds()
, чтобы найти наилучшее значение для baselineShift
, но, возможно, был бы лучший подход.
![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;
}
}
Ответ 3
Вы можете достичь максимальной гравитации, создав собственный класс MetricAffectingSpan
вот код пользовательского класса:
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);
}
}
Применение диапазона:
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);
Вывод:
![введите описание изображения здесь]()
Подробнее о MetricAffectingSpan: http://developer.android.com/reference/android/text/style/MetricAffectingSpan.html
Пользовательская логика MetricAffectingSpan ссылается на: Два разных стиля в одном текстовом режиме с разной степенью тяжести и hieght
Ответ 4
Я реализовал это в одном из своих приложений.
<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" />
В Activity/Frgament.class
myTextView = (TextView) view.findViewById(R.id.txt_formatted_value);
Жесткий код для целей тестирования,
String numberValue = "123.456";
myTextView.setText(UtilityClass.getFormattedSpannedString("RM"+numberValue,
numberValue.length(),0));
Добавьте этот класс в свой пакет,
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);
}
}
Создан метод формата в 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;
}
Используя этот метод, вы можете сделать больше цирка, как изменение стиля текста, отдельно для SuperScript.
Также вы можете добавить верхний индекс справа и слева. (Здесь я прокомментировал весь код, если вы хотите, можете попробовать...)
![введите описание изображения здесь]()
Ответ 5
наилучшим подходящим решением является html.
Я предпочту для этих решений, он поддерживает и все версии Android, а также устройства.
вот пример, возьмите его так же, как текст
<p><sup>TM</sup> 123.456.</p>
Я получаю результат в android
TM 123.456.
вы можете легко отображать текст в Textview в Android с помощью
Html.fromText("YOUR_STRING_INHTML");
Надеюсь, что это поможет.
Ответ 6
вам нужно использовать тег html, как показано ниже для индекса и надстрочного индекса. Он работает как шарм.
((TextView) findViewById(R.id.text)).setText(Html.fromHtml("<sup><small>2</small></sup>X"));
![введите описание изображения здесь]()
или
Вы также можете использовать код ниже:
String titleFirst = "Insert GoTechTM device into the vehicle\ 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);
Ответ 7
Класс для верхнего выравнивания, который следует использовать вместо RelativeSizeSpan (не в дополнение к):
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);
}
}
И использование:
spannableString.setSpan(new TopRelativeSizeSpan(0.50f), 0, index, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(spannableString, TextView.BufferType.SPANNABLE);
Ответ 8
Многие из приведенных здесь ответов требуют, чтобы вы установили процентную шкалу размера текста и угадали смещение, чтобы учесть их ошибку при вычислении правильного смещения, или они требуют, чтобы вы установили несколько интервалов.
Итак, чтобы обновить этот вопрос, вот решение, которое устанавливает правильную базовую линию верхнего индекса и только запрашивает, чтобы вы предоставили процентное значение масштаба текста только для 1 требуемого диапазона:
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)
}
}
Вы можете использовать это, не устанавливая другие промежутки, например так:
val spannableString = SpannableString("RM123.456")
spannableString.setSpan(TopAlignSuperscriptSpan(0.6f), 0, 2, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE)
myTextView.text = spannableString
"RM" будет составлять 60% от размера текста "123,456", а его верх будет точно выровнен с верхом "123,456"
ОБНОВЛЕНИЕ: Вы не должны использовать это, потому что это неточно, как любой другой ответ здесь. Вместо этого я бы предложил рассчитать высоту каждого раздела текстового представления и вручную установить значение y для каждого раздела, как это делает эта библиотека: https://github.com/fabiomsr/MoneyTextView/tree/master/moneytextview/src/Основные /RES/значения
Ответ 9
Я знаю, что это старая ветка, но я только что столкнулся с этим сегодня, и я удивлен, что никто не ответил с этим... Я бы порекомендовал не жестко кодировать 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)