Android

您所在的位置:网站首页 安卓图标角标 Android

Android

2024-07-16 07:47| 来源: 网络整理| 查看: 265

上面两张图,大家应该很熟悉这就是上标和下标的效果,实现代码如下: 上标:

代码1:

SpannableString ss = new SpannableString("RM123.456"); SuperscriptSpan superScriptTextSpan = new SuperscriptSpan(); ss.setSpan(superScriptTextSpan, 0, 2, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE); AbsoluteSizeSpan sizeSpan =new AbsoluteSizeSpan(18,true); ss.setSpan(sizeSpan, 0, 2, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE); tvImageSpan.setText(ss);

效果如图:

代码2:

SpannableString ss = new SpannableString("RM123.456"); AbsoluteSizeSpan sizeSpan =new AbsoluteSizeSpan(18,true); ss.setSpan(sizeSpan, 0, 2, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE); SuperscriptSpan superScriptTextSpan = new SuperscriptSpan(); ss.setSpan(superScriptTextSpan, 0, 2, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE); tvImageSpan.setText(ss);

效果如图: 请大家仔细观察上面两段代码和效果图,可以发现细微差别: 1、代码中设置字体大小和社这上标效果的代码顺序不同; 2、效果图中上标显示的位置不同,先设置上标效果,结果显示靠上,先设字体显示跟其他文字基本顶部对齐,基本达到我们想要的效果。

下标:

代码1:

SpannableString ss = new SpannableString("RM123.456"); AbsoluteSizeSpan sizeSpan =new AbsoluteSizeSpan(18,true); ss.setSpan(sizeSpan, 0, 2, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE); SubscriptSpan superScriptTextSpan = new SubscriptSpan(); ss.setSpan(superScriptTextSpan, 0, 2, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE); tvImageSpan.setText(ss);

效果如图: 代码2:

SpannableString ss = new SpannableString("RM123.456"); SubscriptSpan superScriptTextSpan = new SubscriptSpan(); ss.setSpan(superScriptTextSpan, 0, 2, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE); AbsoluteSizeSpan sizeSpan =new AbsoluteSizeSpan(18,true); ss.setSpan(sizeSpan, 0, 2, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE); tvImageSpan.setText(ss);

效果如图:

同样,请大家仔细观察上面两段代码和效果图,可以发现: 1、代码中设置字体大小和社这上标效果的代码顺序不同; 2、效果图中上标显示的位置不同,先设字体显示跟其他文字底部对齐,先设置下标效果,结果显示截断。

注意: 这里一定要注意设置字体大小,否则,上标和下标将会超出TextView的显示范围被截断。 如下图:

原因也比较简单了,直接看源码: SuperscriptSpan

public class SuperscriptSpan extends MetricAffectingSpan implements ParcelableSpan { public SuperscriptSpan() { } public SuperscriptSpan(Parcel src) { } public int getSpanTypeId() { return getSpanTypeIdInternal(); } /** @hide */ public int getSpanTypeIdInternal() { return TextUtils.SUPERSCRIPT_SPAN; } public int describeContents() { return 0; } public void writeToParcel(Parcel dest, int flags) { writeToParcelInternal(dest, flags); } /** @hide */ public void writeToParcelInternal(Parcel dest, int flags) { } @Override public void updateDrawState(TextPaint tp) { tp.baselineShift += (int) (tp.ascent() / 2); } @Override public void updateMeasureState(TextPaint tp) { tp.baselineShift += (int) (tp.ascent() / 2); } }

SubscriptSpan

public class SubscriptSpan extends MetricAffectingSpan implements ParcelableSpan { public SubscriptSpan() { } public SubscriptSpan(Parcel src) { } public int getSpanTypeId() { return getSpanTypeIdInternal(); } /** @hide */ public int getSpanTypeIdInternal() { return TextUtils.SUBSCRIPT_SPAN; } public int describeContents() { return 0; } public void writeToParcel(Parcel dest, int flags) { writeToParcelInternal(dest, flags); } /** @hide */ public void writeToParcelInternal(Parcel dest, int flags) { } @Override public void updateDrawState(TextPaint tp) { tp.baselineShift -= (int) (tp.ascent() / 2); } @Override public void updateMeasureState(TextPaint tp) { tp.baselineShift -= (int) (tp.ascent() / 2); } }

从源码中我们可以看出,上标SuperscriptSpan,下标SubscriptSpan本身不可以修改大小,只是修改了baselineShift,即修改baseline的位置,而且简单粗暴,直接取ascent的一半进行位移,所以大多数时候肯定达不到我们想要的效果,但这里也给了我们一个启发,我们可以通过修改baselineShift来调整上标或者下标的位置以打到我们想要的效果。

好了,说了这么多,我们该说说我们今天主要讨论的顶部对齐问题了,其实前面也提到了实现方式,这里我尝试了两种方式达到我们要的顶部对齐方式。

修改baselineShift public class SuperScriptTextSpan extends MetricAffectingSpan { private int fontSizeSp = -1; private boolean isSp; public SuperScriptTextSpan(int fontSizeSp, boolean isSp) { this.fontSizeSp = fontSizeSp; this.isSp = isSp; } @Override public void updateDrawState(TextPaint ds) { float ascent = ds.ascent(); Log.d("SuperScriptTextSpan", "ascent-> " + ds.ascent()); if (fontSizeSp != -1) { ds.setTextSize(isSp ? fontSizeSp * ds.density : fontSizeSp); } float newAscent = ds.ascent(); Log.d("SuperScriptTextSpan", "newAscent-> " + ds.ascent()); ds.baselineShift += ascent - newAscent; //方法2: //Rect bounds = new Rect(); //ds.getTextBounds("1A", 0, 2, bounds); //int shift = bounds.top - bounds.bottom; //if (fontSizeSp != -1) { // ds.setTextSize(isSp ? fontSizeSp * ds.density : fontSizeSp); //} //ds.getTextBounds("1A", 0, 2, bounds); //shift += bounds.bottom - bounds.top; //ds.baselineShift += shift; } @Override public void updateMeasureState(TextPaint p) { updateDrawState(p); } } 修改Y坐标 public class SuperScriptTextSpan extends ReplacementSpan { private int fontSizeSp = -1; private boolean isSp; public SuperScriptTextSpan(int fontSizeSp, boolean isSp) { this.fontSizeSp = fontSizeSp; this.isSp = isSp; } @Override public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fm) { Paint newPaint = getCustomTextPaint(paint); return (int) newPainasureText(text, start, end); } @Override public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) { Paint newPaint = getCustomTextPaint(paint); Paint.FontMetricsInt fontMetricsInt = newPaint.getFontMetricsInt(); canvas.drawText(text, start, end, x, y + fontMetricsInt.ascent, newPaint); } private TextPaint getCustomTextPaint(Paint srcPaint) { TextPaint textPaint = new TextPaint(srcPaint); if (fontSizeSp != -1) { textPaint.setTextSize(isSp ? fontSizeSp * textPaint.density : fontSizeSp); } return textPaint; } }

MainActivity.java

SpannableString ss = new SpannableString("RM123.456"); SuperScriptTextSpan superScriptTextSpan = new SuperScriptTextSpan(18,true); ss.setSpan(superScriptTextSpan, 0, 2, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE); tvImageSpan.setText(ss);

这两个方法都非常的简单,而且可以修改字体大小哦。 这些方法中,我觉得最省事就是直接修改Y坐标,快准狠,哈哈,而且效果也是最满意的,跟其他文字完全顶部对齐。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3