浅谈 TextView 中的多样式文本

我们用xml布局的时候,一个TextView通常只能拥有一个显示样式,如textSize,textColor等.当需要想突出显示TextView中的一些字符或文本的话,应该怎么办呢?

string.xml


在string.xml 中,我们可以对字符串做一些简单的样式更改,如下
将wall 的字体颜色置为红色,大小置为50sp

  Humpty Dumpty sat on a wall

tips:

  1. 红色的颜色代码为#FFFFFFFF ,但如果直接设为fgcolor="#ffff0000" 则不能奏效,甚至会导致目标文本消失. 这是由于颜色的16进制值导致的,简单的方法就是取值为0x100000000 -0xffff0000= 0x10000 再取反,就能成功设置为红色.
  2. size中的值单位为dp

Html.fromHtml()


较简易的方法是用Html语法,再使用Html.fromHtml() 转化为有样式的字符串,如下

      mTextView.setText(Html.fromHtml("Some radom Color"));

自定义Span


Spanned 是 CharSequence 的子类,这意味着它也可以在TextVIew中显示,Android 中有各种类型的span

  1. AbsoluteSizeSpan 指定字体大小
  2. BackgroundColorSpan 指定文本背景色
  3. BulletSpan 在文本前显示圆点 ,类似html中的
  4. 效果
  5. DrawableMarginSpan,IconMarginSpan,ImageSpan 文本中添加图片
  6. ForegroundColorSpan 改变字体颜色
  7. LeadingMarginSpan 调整文本缩进
  8. ScaleXSpan 横向缩放文本
  9. StrikethroughSpan 添加删除线
  10. StyleSpan 添加 正常,粗体,斜体样式
  11. SubscriptSpan 下标样式
  12. SuperscriptSpan 上标样式
  13. TextAppearanceSpan 按照资源中的样式表R.style.my_style 来为文本添加样式
  14. TypefaceSpan 设置字体
  15. UnderlineSpan 下划线样式
  16. URLSpan 可点击打开链接
  17. ClickableSpan 抽象类,可以自定义文本点击方法

注意,设置span比较消耗资源,如果可以,在后台线程中操作再设置到控件中.

构建自定义span 主要用到的是SpannableStringSpannableStringBuilder这两个类
一般用法就是 先创建所需的Span,再用setSpan() 方法来进行设置.

tips:

  • ClickableSpan 点击后会出现文本背景色发生变化的情况, 可以在onClick事件中设置控件重绘来解决,如下
  public class LinkClickSpan extends ClickableSpan {
        AffLinkModel mLinkModel;

        public LinkClickSpan(AffLinkModel linkModel) {
            mLinkModel = linkModel;
        }

        @Override
        public void onClick(View widget) {
            Logger.t("method").i("click");
            AffLinkDialog.getInstance(mLinkModel).show(getChildFragmentManager(), null);
            widget.invalidate();
        }


    }
  • 如果想用正则表达式将一段文本中特定文本标记或替换,可以使用这个类Replacer,如下
/**
 * 文本正则替换器
 * 支持替换将包含"<...>","[...]"的文本,变为去掉括号,并修改颜色和字体大小
 * Author: yanhao([email protected])
 * Date : 2016-01-14
 * Time: 15:21
 */
public class Replacer {
    private static final String TAG = "Replacer";
    private final CharSequence mSource;//需要修改的文本
    private final CharSequence mReplacement;//待替换的文本
    private final Matcher mMatcher;//正则匹配器
    private int mAppendPosition;//当前builder所在位置
    private final boolean mIsSpannable;//代替换的样式字符串是否存在样式

    //将符合正则的文本替换为指定文本
    public static CharSequence replace(CharSequence source,String regex, CharSequence replacement){
        Pattern pattern=Pattern.compile(regex);
        Matcher matcher=pattern.matcher(source);
        return new Replacer(matcher,replacement,source).doReplace();
    }
    //将符合正则的文本替换为指定文本 并修改字体大小和字体颜色
    public static CharSequence replaceWithColorAndSize(CharSequence source,String regex,int color,int sizeIndp){
        Pattern pattern=Pattern.compile(regex);
        Matcher matcher=pattern.matcher(source);
        return new Replacer(matcher,null,source).doOriginReplace(color,sizeIndp);
    }

    public Replacer(Matcher matcher, CharSequence replacement, CharSequence source) {
        mMatcher = matcher;
        mReplacement = replacement;
        mSource = source;
        mAppendPosition = 0;
        mIsSpannable = replacement instanceof Spannable;
    }
    //执行简单替换的功能
    private CharSequence doReplace() {
        SpannableStringBuilder builder = new SpannableStringBuilder();
        while (mMatcher.find()) {
            appendRelacement(builder);
        }
        return appendTail(builder);
    }
    //执行替换原文本,并指定替换的字体大小和颜色
    private CharSequence doOriginReplace(int color,int textSize){
        SpannableStringBuilder builder = new SpannableStringBuilder();
        while (mMatcher.find()) {
            try {
                CharSequence charSource = mSource.subSequence(mMatcher.start()+1, mMatcher.end()-1);
                //更换字体颜色
                ForegroundColorSpan colorSpan=new ForegroundColorSpan(color);
                //更换字体大小
                AbsoluteSizeSpan sizeSpan=new AbsoluteSizeSpan(textSize,false);
                SpannableStringBuilder stringBuilder=new SpannableStringBuilder(charSource);
                stringBuilder.setSpan(colorSpan, 0, charSource.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                stringBuilder.setSpan(sizeSpan, 0, charSource.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                appendRelacement(builder, stringBuilder);
            } finally {
                continue;
            }
        }
        return appendTail(builder);
    }


    private void appendRelacement(SpannableStringBuilder builder) {
        builder.append(mSource.subSequence(mAppendPosition, mMatcher.start()));
        CharSequence replacement = mIsSpannable
                ? copyCharSequenceWithSpans(mReplacement)
                : mReplacement;
        builder.append(replacement);
        mAppendPosition = mMatcher.end();
    }
    private void appendRelacement(SpannableStringBuilder builder,CharSequence tempReplace) {
        builder.append(mSource.subSequence(mAppendPosition, mMatcher.start()));
        builder.append(tempReplace);
        mAppendPosition = mMatcher.end();
    }

    private CharSequence copyCharSequenceWithSpans(CharSequence string) {
        Parcel parcel = Parcel.obtain();
        try {
            TextUtils.writeToParcel(string, parcel, 0);
            parcel.setDataPosition(0);
            return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
        } finally {
            parcel.recycle();
        }
    }

    private CharSequence appendTail(SpannableStringBuilder builder) {
        builder.append(mSource.subSequence(mAppendPosition, mSource.length()));
        return builder;
    }
}

你可能感兴趣的:(浅谈 TextView 中的多样式文本)