我有以下字符串 RM123.456 。我想
我几乎可以通过
来实现它spannableString.setSpan(new RelativeSizeSpan(0.50f), 0, index, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(spannableString, TextView.BufferType.SPANNABLE);
结果如下
然而,它与底部对齐。它没有与顶部对齐。
我尝试使用SuperscriptSpan
。它看起来像
它没有做我想要的
SuperscriptSpan
不会使文字变小。我无法控制它的尺寸。SuperscriptSpan
会使文字“超过顶部对齐”我可以知道,如何让RelativeSizeSpan与完全对齐?
这就是我希望实现的目标。
请注意,我们不希望使用2 TextViews解决方案。
答案 0 :(得分:20)
但是我这样做了:
<强> 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 );
}
}
希望这会对你有所帮助。
答案 1 :(得分:12)
我查看了RelativeSizeSpan
,发现了一个相当简单的实现。因此,您可以为自己的目的实施自己的RelativeSizeSpan
。这里唯一的区别是它没有实现ParcelableSpan
,因为这仅用于框架代码。 AntiRelativeSizeSpan
只是一个快速的黑客,当然没有太多的测试,但似乎工作正常。它完全依赖于Paint.getTextBounds()
来找到baselineShift
的最佳价值,但也许有更好的方法。
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;
}
}
答案 2 :(得分:10)
您可以通过创建自定义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);
<强>输出:强>
Custom MetricAffectingSpan逻辑来自:http://developer.android.com/reference/android/text/style/MetricAffectingSpan.html
答案 3 :(得分:8)
最合适的解决方案是使用html。
我更喜欢这个解决方案,它支持所有Android版本以及设备。
这里的示例与您想要的文本相同
<p><sup>TM</sup> 123.456.</p>
我在android中获得结果
TM 123.456。
您可以使用
在Android中的Textview中轻松显示文本 Html.fromText("YOUR_STRING_INHTML");
希望它有所帮助。
答案 4 :(得分:8)
我已经在我的一个应用程序中实现了这个。
<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 :(得分:6)
你必须使用下面的html标签作为下标和上标。它就像魅力一样。
((TextView) findViewById(R.id.text)).setText(Html.fromHtml("<sup><small>2</small></sup>X"));
或
您还可以使用以下代码:
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 :(得分:0)
顶部对齐的类,应该使用而不是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);
答案 7 :(得分:0)
此处提供的许多答案都要求您设置文本大小比例百分比,并猜测一个偏移量以解决他们在计算正确的偏移量时的错误,或者要求您设置多个跨度。
因此,要更新此问题,以下是一个解决方案,该解决方案可以设置上标的正确基线,并且仅要求您为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”将是“ 123.456”文本大小的60%,并且其顶部将与“ 123.456”的顶部完全对齐
更新:您不应使用它,因为它不精确,就像这里的所有其他答案一样。 相反,我建议计算文本视图每个部分的高度,并手动设置每个部分的y值,就像该库一样:https://github.com/fabiomsr/MoneyTextView/tree/master/moneytextview/src/main/res/values
答案 8 :(得分:0)
我知道这是一个旧线程,但是我今天才碰到这个问题,我很惊讶没有人回答这个问题……我建议不要对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)