• Android TextView富文本SpannableStringBuilder的使用详解


    背景:

    android开发过程中,做内容的时候,不仅只有字符,基本都是图文混排,甚至还会对内容中某段文字进行特殊处理,比如:字体加粗、字体变大、改变字体颜色、对某一段文字新增点击事件,等等。这些内容不可能通过一个一个view去拼接,这么复杂的其实可以通过一个textview控件就可以完成,但是需要搭配一个助手

    SpannableStringBuilder:

    可生成字符串生成器,这是内容和标记都可以更改的文本类。常见的富文本修饰如:新增、删除、字体颜色、大小、背景色、图片、上标、下标、删除、点击等,接下来我们将介绍常用的一些

    一、SpannableStringBuilderAPI介绍

    1.初始化:

    1.1创建一个空对象

    public SpannableStringBuilder() {
        this("");
    }

    1.2 创建其中包含指定的文本,包括其跨度

    public SpannableStringBuilder(CharSequence text) {
        this(text, 0, text.length());
    }

    1.3创建一个对象,包含指定的文本,指定文本内容的起始和结束

    public SpannableStringBuilder(CharSequence text, int start, int end)

    2.API的使用

    2.1类型转换:

    public static SpannableStringBuilder valueOf(CharSequence source)

    如果source是SpannableStringBuilder将直接强行转换,否则new一个新的对象,这个方法也使用创建对象使用。

    2.2返回SpannStringBuild的内容指定的下标字符

    public char charAt(int where)
    

    如果当前内容为:ABCDE

    那么charAt(int 0)返回A,否则会出现数组越界等问题

    2.3追加内容

    public SpannableStringBuilder append(CharSequence text)

    2.4从指定的位置插入内容

    public SpannableStringBuilder insert(int where, CharSequence tb)

    weher是要插入的地方,插入进去,原来内容会接在新的后面

    oldTxt="ABCDEFG"

    newTxt="abcdefg"

    where=5

    buildText="ABCDEabcdefgFG"

    2.5删除内容,从哪个位置开始,删除到哪里

    public SpannableStringBuilder delete(int start, int end) 

    2.6设置Span样式,可以支持多个span

    public void setSpan(Object what, int start, int end, int flags)
    

    what:Span对象,是一个object,这些Span都在android.text.style包下。

    start:内容的起始位置

    end:内容的结束位置

    flags:默认使用SPAN_EXCLUSIVE_EXCLUSIVE

    SPAN_EXCLUSIVE_INCLUSIVE:类型的非0长度跨度展开包括在其终点插入但不在其终点处插入的文本起点。当长度为0时,它们的行为类似于点。
    SPAN_EXCLUSIVE_EXCLUSIVE:类型的跨度不展开以包括在其起点或终点插入的文本。它们的长度永远不能为0,并且会自动删除如果它们覆盖的所有文本都被删除,则从缓冲区中删除
    SPAN_INCLUSIVE_INCLUSIVE:类型的跨度展开以包括在其起点或终点插入的文本。
    SPAN_INCLUSIVE_EXCLUSIVE:类型的非0长度跨度展开包括在起点插入但不在起点插入的文本结束点。当长度为0时,它们的行为类似于标记。

    常见的Span使用

    3.1 AbsoluteSizeSpan:设置字体大小

    默认是px像素,可以在构造时指定为dp

    1. SpannableStringBuilder builder=new SpannableStringBuilder(msg);
    2. AbsoluteSizeSpan absoluteSizeSpan=new AbsoluteSizeSpan(30,true);
    3. builder.setSpan(absoluteSizeSpan,0,10, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
    4. text_span.setText(builder);

    注意://text在设置的时候,不要将build转成toString个(),否则会出现不生效

    AbsoluteSizeSpan
    AbsoluteSizeSpan

    3.2:BackgroundColorSpan设置背景色

    1.初始化
    public BackgroundColorSpan(int color) {
        mColor = color;
    }

    2.初始化
    public BackgroundColorSpan(Parcel src) {
        mColor = src.readInt();
    }

    初始化两种方式,第一种直接给出涂颜色color,第二种将颜色序列化

    1. BackgroundColorSpan colorSpan=new BackgroundColorSpan(Color.RED);
    2. builder.setSpan(colorSpan,0,10, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
    3. text_span.setText(builder);
    BackgroundColorSpan

    3.3 BulletSpan距离左边的宽度

    public BulletSpan(int gapWidth, int color)
    BulletSpan bulletSpan = new BulletSpan(40,Color.RED);

    gapWidth: 距左边的距离

    color:小球色值

    这个小球点默认半径是很小,固定值,在更高的API中,半径是可以修改,或者自己扩展也可以

    1. BulletSpan bulletSpan = new BulletSpan(40,Color.RED);
    2.  builder.setSpan(bulletSpan, 0, 5, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); text_span.setText(builder);

    注意:起始位置只有是从最左边开始,如果内容在中间,将不生效

     
    
    BulletSpan

    3.4 DrawableMarginSpan边缘draw

    1. DrawableMarginSpan drawableMarginSpan=new DrawableMarginSpan(getDrawable(R.drawable.ask_answer_tag2));
    2. builder.setSpan(drawableMarginSpan,10,10, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
    3. text_span.setText(builder);

    这个设置完只会在最左边显示,所以不管start和end起始和结束位置在哪,都会显示在最左边。如果出现没有效果,可能是因为start!=end,把这两个值设置一样即可

    DrawableMarginSpan

    3.5 ForegroundColorSpan 设置文本字体颜色

    1. ForegroundColorSpan foregroundColorSpan=new ForegroundColorSpan(Color.RED);
    2. builder.setSpan(foregroundColorSpan,0,10, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
    3. text_span.setText(builder);
    ForegroundColorSpan

    3.6 IconMarginSpan:首占位符为图片

    IconMarginSpan和DrawMarginSpan用法一样,都是作为icon在最顶部出现,不受start和end位置影响。
    1. Bitmap bitmap= BitmapFactory.decodeResource(getResources(),R.drawable.ask_answer_tag2);
    2. IconMarginSpan iconMarginSpan=new IconMarginSpan(bitmap);
    3. builder.setSpan(iconMarginSpan,10,10, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
    4. text_span.setText(builder);
    IconMarginSpan

     3.6 ImageSpan图片跨度

    1. ImageSpan imageSpan=new ImageSpan(bitmap);
    2. builder.setSpan(imageSpan,10,20, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
    3. text_span.setText(builder);

    ImageSpan与IconMarginSpan、DrawMarginSpan的效果不一样,ImageSpan会占用文本位置,也就是说start和end这中间的内容会被图片覆盖了,而且end>start。

    ImageSpan

    3.7  MaskFilterSpan 掩码筛选器范围

    常见的Maskfilter如下:

    EmbossMaskFilter:浮雕

    BlurMaskFilter:模糊

    BlurMaskFilter的使用:也可以实现高斯模糊效果
    
    public BlurMaskFilter(float radius, Blur style) 

    radius:模糊半径,必须>0

    style:
    Blur.NORMAL:正常

    Blur.SOLID:加粗

    Blur.OUTER:外部

    Blur.INNER:内部

    1. private void setTextColor() {
    2. // msg=getString(R.string.hellow);
    3. SpannableStringBuilder builder = new SpannableStringBuilder(msg);
    4. // text_span.setText(""+builder.charAt(1));
    5. // text_span.setText(builder.append("new123"));
    6. AbsoluteSizeSpan absoluteSizeSpan = new AbsoluteSizeSpan(30, true);
    7. // builder.setSpan(absoluteSizeSpan,0,10, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
    8. BackgroundColorSpan colorSpan = new BackgroundColorSpan(Color.RED);
    9. // builder.setSpan(colorSpan,0,10, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
    10. BulletSpan bulletSpan = new BulletSpan(100);
    11. DrawableMarginSpan drawableMarginSpan = new DrawableMarginSpan(getDrawable(R.drawable.ask_answer_tag2));
    12. Intent intent = new Intent(this, SimpleWebViewActivity.class);
    13. ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.RED);
    14. Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ask_answer_tag2);
    15. IconMarginSpan iconMarginSpan = new IconMarginSpan(bitmap);
    16. ImageSpan imageSpan = new ImageSpan(bitmap, 100);
    17. LocaleSpan localeSpan = new LocaleSpan(Locale.ENGLISH);
    18. MaskFilter maskFilter = new MaskFilter();
    19. // EmbossMaskFilter embossMaskFilter=new EmbossMaskFilter();
    20. seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
    21. @Override
    22. public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    23. text_progress.setText(textMsg + progress);
    24. BlurMaskFilter blurMaskFilter = new BlurMaskFilter(progress, blur);
    25. MaskFilterSpan maskFilterSpan = new MaskFilterSpan(blurMaskFilter);
    26. builder.setSpan(maskFilterSpan, 0, 20, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
    27. text_span.setText(builder);
    28. }
    29. @Override
    30. public void onStartTrackingTouch(SeekBar seekBar) {
    31. }
    32. @Override
    33. public void onStopTrackingTouch(SeekBar seekBar) {
    34. }
    35. });
    36. }
    37. public void setStyle(View view) {
    38. int id = view.getId();
    39. switch (id) {
    40. case R.id.normal: {
    41. blur= BlurMaskFilter.Blur.NORMAL;
    42. textMsg="NORMAL raduis=";
    43. }
    44. break;
    45. case R.id.solid: {
    46. blur= BlurMaskFilter.Blur.SOLID;
    47. textMsg="SOLID raduis=";
    48. }
    49. break;
    50. case R.id.out: {
    51. blur= BlurMaskFilter.Blur.OUTER;
    52. textMsg="OUTER raduis=";
    53. }
    54. break;
    55. case R.id.inner: {
    56. blur= BlurMaskFilter.Blur.INNER;
    57. textMsg="INNER raduis=";
    58. }
    59. break;
    60. }
    61. }

     
    

    BlurMaskFilter
    MaskFilterSpan 

    EmbossMaskFilter:浮雕

    改方法在textview的api这块,直接使用看不出来效果,下面我将会通过自定义view来做一个效果

    3.8 QuoteSpan:引用,在内容最左侧会有一条竖线

    color:引用线的颜色

    1. QuoteSpan quoteSpan = new QuoteSpan(Color.RED);
    2. builder.setSpan(quoteSpan, 0, builder.length(), SpannableStringBuilder.SPAN_INCLUSIVE_EXCLUSIVE);
    3. text_new.setText(builder);

    QuoteSpan

    3.9 RelativeSizeSpan:相对大小,将原来的textsize放大或缩小相应的倍数

    1. RelativeSizeSpan relativeSizeSpan=new RelativeSizeSpan(2f);
    2. builder.setSpan(relativeSizeSpan, 0, builder.length(), SpannableStringBuilder.SPAN_INCLUSIVE_EXCLUSIVE);
    3. text_new.setText(builder);
    RelativeSizeSpan

    3.10 ScaleXSpan :水平缩放
     

    1. ScaleXSpan scaleXSpan=new ScaleXSpan(0.5f);
    2. //proportion:缩放倍数
    3. builder.setSpan(scaleXSpan, 0, builder.length(), SpannableStringBuilder.SPAN_INCLUSIVE_EXCLUSIVE);
    4. text_new.setText(builder);

    ScaleXSpan

    3.11 StrikethroughSpan:删除线(非下划线)

    1. StrikethroughSpan span=new StrikethroughSpan();
    2. builder.setSpan(span, 0, builder.length(), SpannableStringBuilder.SPAN_INCLUSIVE_EXCLUSIVE);
    3. text_new.setText(builder);
    StrikethroughSpan

    3.12 StyleSpan :内容style设置,该方法和textview的style一致,
     

    /**
     * 
     * @param style An integer constant describing the style for this span. Examples
     * include bold, italic, and normal. Values are constants defined 
     * in {@link android.graphics.Typeface}.
     */
    public StyleSpan(int style) {
        mStyle = style;
    }
    // Style
    public static final int NORMAL = 0;//正常
    public static final int BOLD = 1;//加粗
    public static final int ITALIC = 2;//斜体
    public static final int BOLD_ITALIC = 3;//加粗斜体
    1. styleSpan=new StyleSpan(Typeface.BOLD);
    2. builder.setSpan(styleSpan, 0, builder.length(), SpannableStringBuilder.SPAN_INCLUSIVE_EXCLUSIVE);
    3. text_new.setText(builder);
    StyleSpan

    3.12 SubscriptSpan:下标(常见化学公式)

    1. SubscriptSpan subscriptSpan=new SubscriptSpan();
    2. builder.setSpan(subscriptSpan, 0, 2, SpannableStringBuilder.SPAN_INCLUSIVE_EXCLUSIVE);
    3. text_new.setText(builder);
    4.  


     

    SubscriptSpan

    3.14 SuperscriptSpan:上标(常见化学公式)

    1. SuperscriptSpan superscriptSpan=new SuperscriptSpan();
    2. builder.setSpan(superscriptSpan, 2, 3, SpannableStringBuilder.SPAN_INCLUSIVE_EXCLUSIVE);
    3. text_new.setText(builder);
    SuperscriptSpan

    3.15 UnderlineSpan:下划线

    1. UnderlineSpan underlineSpan=new UnderlineSpan();
    2. builder.setSpan(underlineSpan, 2, builder.length(), SpannableStringBuilder.SPAN_INCLUSIVE_EXCLUSIVE);
    3. text_new.setText(builder);
    UnderlineSpan

    3.16 URLSpan :连接跳转

    1. URLSpan  urlSpan=new URLSpan("http://www.baidu.com");
    2. builder.insert(4,"点击百度");
    3. builder.setSpan(underlineSpan, 4, 8, SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE);
    4. builder.setSpan(urlSpan, 4, 8, SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE);
    5. text_new.setText(builder);
    6. text_new.setMovementMethod(LinkMovementMethod.getInstance());

    URLSpan

    注意:

    1、如果不设置text_new.setMovementMethod(LinkMovementMethod.getInstance());方法,在点击事件触发可能失效。

    2、URLSpan如果url直接是www.baidu.com无法启动,所以需要加上http://或者https://头部

    3.17 ClickableSpan:点击事件拦截

    1. ClickableSpan clickableSpan=new ClickableSpan() {
    2. @Override
    3. public void onClick(@NonNull View widget) {
    4. Uri uri = Uri.parse("http://www.baidu.com");
    5. Context context = widget.getContext();
    6. Intent intent = new Intent(Intent.ACTION_VIEW, uri);
    7. intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
    8. try {
    9. context.startActivity(intent);
    10. } catch (ActivityNotFoundException e) {
    11. Log.w("URLSpan", "Actvity was not found for intent, " + intent.toString());
    12. }
    13. }
    14. };
    15. builder.insert(4,"点击安卓");
    16. // builder.setSpan(underlineSpan, 4, 8, SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE);
    17. builder.setSpan(clickableSpan, 4, 8, SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE);
    18. text_new.setText(builder);
    19. text_new.setMovementMethod(LinkMovementMethod.getInstance());
    20.  
    ClickableSpan
  • 相关阅读:
    第三章:Java运算符
    阿里云服务器+Frp+Proxifier工具进行内网穿透
    算法与数据结构(一)————入门专栏介绍
    云栖大会,未来万物皆是计算机?
    半入耳蓝牙耳机哪款好用?南卡和FIIL半入耳耳机测评
    立方尾不变:(BigInteger、multiply、toString()、endsWith()、String.valueOf())
    【Python如何与电脑玩石头剪刀布游戏】
    美团校招机试 - 小美的MT(20240309-T3)
    opencv之图像元素遍历(反色) 笔记
    哪款半入耳式蓝牙耳机音质好?音质比较好的半入耳式蓝牙耳机推荐
  • 原文地址:https://blog.csdn.net/qq36246172/article/details/127657742