如何使用占位符在TextView的带格式文本上设置多个跨度,使用自定义范围?

时间:2017-04-20 11:22:11

标签: android textview spannablestring

背景

我知道如何在静态文本中的部分文本上设置多个跨度,因为我已经问过here

final SpannableString text = new SpannableString("Hello stackOverflow");
text.setSpan(new RelativeSizeSpan(1.5f), text.length() - "stackOverflow".length(), text.length(),
            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
text.setSpan(new ForegroundColorSpan(Color.RED), 3, text.length() - 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.setText(text);

这会将“stackOverflow”设置为自身有2个跨度。

我也知道如何在文本的一部分上设置可绘制的跨度,因为我已经问过here

问题

现在我需要在通过使用占位符格式化文本生成的文本上设置2个跨度,同时仍然像往常一样设置其他样式。

例如,假设我在strings.xml中有下一个文本:

<string name="potential_free_upgrade_1_d_months">
    <![CDATA[
    Potential free upgrade: <uu><b><font color=\'#3792e5\'>%1$d months</font></b></uu>]]>
</string>

enter image description here

计划是“%1 $ d个月”的文字颜色为“#3792e5”,并且会有一个比默认颜色略低的特殊下划线。我使用特殊的自定义标签“uu”作为特殊下划线,用代码处理。

事情是,无论我做什么,我都找不到如何同时显示文字颜色和下划线。

我尝试了什么

由于此问题有一个占位符(并且文本可能在要格式化的文本周围不同),我不得不使用“Html.FromHtml”:

    String formattedStr = getString(R.string.potential_free_upgrade_1_d_months, 9);
    Spanned textToShow = Html.fromHtml(formattedStr, null, new TagHandler() {
        int start;

        @Override
        public void handleTag(final boolean opening, final String tag, Editable output, final XMLReader xmlReader) {
            switch (tag) {
                case "uu":
                    if (opening)
                        start = output.length();
                    else {
                        int end = output.length();
                        //output.setSpan(new ForegroundColorSpan(0xff3792e5), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                        output.setSpan(
                                new DrawableSpan(ResourcesCompat.getDrawable(getResources(), R.drawable.bit_below_underline, null)),
                                start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                    }
            }
        }
    });
    titleTextView.setText(textToShow);

DrawableSpan.java

public class DrawableSpan extends ReplacementSpan {
    private Drawable mDrawable;
    private final Rect mPadding;

    public DrawableSpan(Drawable drawable) {
        super();
        mDrawable = drawable;
        mPadding = new Rect();
        mDrawable.getPadding(mPadding);
    }

    @Override
    public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) {
        RectF rect = new RectF(x, top, x + measureText(paint, text, start, end), bottom);
        mDrawable.setBounds((int) rect.left - mPadding.left, (int) rect.top - mPadding.top, (int) rect.right + mPadding.right, (int) rect.bottom + mPadding.bottom);
        canvas.drawText(text, start, end, x, y, paint);
        mDrawable.draw(canvas);
    }

    @Override
    public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
        return Math.round(paint.measureText(text, start, end));
    }

    private float measureText(Paint paint, CharSequence text, int start, int end) {
        return paint.measureText(text, start, end);
    }
}

RES /抽拉/ bit_below_underline.xml

<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="line">
    <padding android:bottom="30dp"/>
    <stroke
        android:width="1dp"
        android:color="#3792e5"/>
</shape>

我试图将2“setSpan”一起调用(首先在上面的代码中注释),但它没有帮助。

问题

如何在文本部分设置2个跨度,如上所述(带占位符的部分文本),以便一个是文本颜色,另一个是自定义下划线?

1 个答案:

答案 0 :(得分:0)

在测试代码时,似乎div在任何ReplacementSpans之前被绘制。因此,请尝试使用CharacterStyleSpan。它将在MetricAffectingSpan之前绘制。

因此,请使用自定义ReplacementSpans代替MetricAffectingSpan

ForegroundColorSpan
好的。我试图从android SDK源代码解释这个问题,在这个for循环中有import android.text.TextPaint; import android.text.style.MetricAffectingSpan; public class BGColorSpan extends MetricAffectingSpan { private int color; public BGColorSpan(int color) { this.color = color; } @Override public void updateMeasureState(TextPaint textPaint) { textPaint.setColor(color); } @Override public void updateDrawState(TextPaint textPaint) { textPaint.setColor(color); } } 个关键字,它将跳过continue的呈现

CharacterStyleSpan