Android TextView设置部分文字的颜色字体和大小

目录

         一,通过Html实现

1,例如实现如下效果

2,为一段文字中某些字单独设置字体大小

       3,设置字体

二,通过Span

相关知识


前言

有时候一个TextView显示很多文字,所有文字颜色,字体,大小不统一;这个时候就需要单独设置某些字;

一,通过Html实现

1,例如实现如下效果

1.1,为一段文字中某些字单独设置一种颜色

通过Html.fromHtml(String source)方法实现

String str1 = "微信扫码<font color = '#FFB400'>关注公众号</font>,立即开始";
textView.setText(Html.fromHtml(str1));

注意:fromHtml(String source)在PI Level 24以上已废弃,API Level 24或以上的设备则使用2个参数的方法即可。fromHtml(String source, int flags)

 String str1 = "微信扫码<font color = '#FFB400'>关注公众号</font>,立即开始";

CharSequence charSequence;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
     charSequence = Html.fromHtml(str1, Html.FROM_HTML_MODE_LEGACY);
} else {
     charSequence = Html.fromHtml(str1);
}
textView.setText(charSequence);

flags可选参数:

public static final int FROM_HTML_MODE_COMPACT = 63;
public static final int FROM_HTML_MODE_LEGACY = 0;
public static final int FROM_HTML_OPTION_USE_CSS_COLORS = 256;
public static final int FROM_HTML_SEPARATOR_LINE_BREAK_BLOCKQUOTE = 32;
public static final int FROM_HTML_SEPARATOR_LINE_BREAK_DIV = 16;
public static final int FROM_HTML_SEPARATOR_LINE_BREAK_HEADING = 2;
public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST = 8;
public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM = 4;
public static final int FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH = 1;
public static final int TO_HTML_PARAGRAPH_LINES_CONSECUTIVE = 0;
public static final int TO_HTML_PARAGRAPH_LINES_INDIVIDUAL = 1;

1.2,为一段文字中某些字单独设置多种颜色

效果图

TextView tv = findViewById(R.id.tv);
String text1 = "<font color = '#FF0000'>床前明月光,</font><br>";
String text2 = "<font color='#00FF00'>疑是地上霜。</font><br>";
String text3 = "<font color=\"#FF00FF\">举头望明月,</font><br>";
String text4 = "<font color=\"#0000FF\">低头思故乡。</font><br>";

CharSequence charSequence;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
    charSequence = Html.fromHtml(text1 + text2 + text3 + text4, Html.FROM_HTML_MODE_LEGACY);
} else {
    charSequence = Html.fromHtml(text1 + text2 + text3 + text4);
}

tv.setText(charSequence);

2,为一段文字中某些字单独设置字体大小

2.1,下面是在xml中设置了android:textSize="30sp"属性,然后java代码中设置了<big>和<small>

        TextView tv = findViewById(R.id.tv);
        String text1 = "<font color = '#FF0000'><big>床前明月光,</big></font><br>";
        String text2 = "<font color='#00FF00'><small>疑是地上霜。</small></font><br>";
        String text3 = "<font color=\"#FF00FF\">举头望明月,</font><br>";
        String text4 = "<font color=\"#0000FF\">低头思故乡。</font><br>";

        CharSequence charSequence;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
            charSequence = Html.fromHtml(text1 + text2 + text3 + text4, Html.FROM_HTML_MODE_LEGACY);
        } else {
            charSequence = Html.fromHtml(text1 + text2 + text3 + text4);
        }

        tv.setText(charSequence);

注意:<big>和<small>标签,设置的大小都是在android:textSize="30sp"这个基础上进行放大缩小的;

2.2,自定义Html.TagHandler设置字体大小

要实现的效果如下:

由于Android对html标签支持不是太好,在将font标签中的size进行赋值后发现大小的设置并没有生效,随后我查看了源码,发现源码中并没有解析size属性,源码如下:

private void startFont(Editable text, Attributes attributes) {
        String color = attributes.getValue("", "color");
        String face = attributes.getValue("", "face");

        if (!TextUtils.isEmpty(color)) {
            int c = getHtmlColor(color);
            if (c != -1) {
                start(text, new Foreground(c | 0xFF000000));
            }
        }

        if (!TextUtils.isEmpty(face)) {
            start(text, new Font(face));
        }
}

所以如果需要支持size属性,需要自定义Html.TagHandler

TextView tv = findViewById(R.id.tv);
        
        String str = "床前明月光";
        String str1 = "疑是地上霜。";
        String text = "<b><myfont size='80px' color='#FF0000'>" + str + "</myfont><br>"
                + "<myfont color='" + "#00FF00" + "', size='" + "40px" + "'>" + str1 + "</myfont>";

        CharSequence charSequence;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
            charSequence = Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY,null,new HtmlTagHandler("myfont"));
        } else {
            charSequence = Html.fromHtml(text, null, new HtmlTagHandler("myfont"));
        }

        tv.setText(charSequence);

自定义Html.TagHandler 

import android.graphics.Color;
import android.text.Editable;
import android.text.Html;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.ForegroundColorSpan;

import org.xml.sax.XMLReader;

import java.lang.reflect.Field;
import java.util.HashMap;

public class HtmlTagHandler implements Html.TagHandler {
    private String tagName;

    private int startIndex = 0;

    private int endIndex = 0;

    final HashMap<String, String> attributes = new HashMap<>();

    public HtmlTagHandler(String tagName) {
        this.tagName = tagName;
    }

    @Override
    public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
        // 判断是否是当前需要的tag
        if (tag.equalsIgnoreCase(tagName)) {
            // 解析所有属性值
            parseAttributes(xmlReader);

            if (opening) {
                startHandleTag(tag, output, xmlReader);
            } else {
                endEndHandleTag(tag, output, xmlReader);
            }
        }
    }

    public void startHandleTag(String tag, Editable output, XMLReader xmlReader) {
        startIndex = output.length();
    }

    public void endEndHandleTag(String tag, Editable output, XMLReader xmlReader) {
        endIndex = output.length();

        // 获取属性值
        String color = attributes.get("color");
        String size = attributes.get("size");
        size = size.split("px")[0];

        // 设置字体大小
        if (!TextUtils.isEmpty(size)) {
            output.setSpan(new AbsoluteSizeSpan(Integer.parseInt(size)), startIndex, endIndex,
                    Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        }

        // 设置颜色
        if (!TextUtils.isEmpty(color)) {
            output.setSpan(new ForegroundColorSpan(Color.parseColor(color)), startIndex, endIndex,
                    Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
    }

    /**
     * 解析所有属性值
     *
     * @param xmlReader
     */
    private void parseAttributes(final XMLReader xmlReader) {
        try {
            Field elementField = xmlReader.getClass().getDeclaredField("theNewElement");
            elementField.setAccessible(true);
            Object element = elementField.get(xmlReader);
            Field attsField = element.getClass().getDeclaredField("theAtts");
            attsField.setAccessible(true);
            Object atts = attsField.get(element);
            Field dataField = atts.getClass().getDeclaredField("data");
            dataField.setAccessible(true);
            String[] data = (String[]) dataField.get(atts);
            Field lengthField = atts.getClass().getDeclaredField("length");
            lengthField.setAccessible(true);
            int len = (Integer) lengthField.get(atts);
            for (int i = 0; i < len; i++) {
                attributes.put(data[i * 5 + 1], data[i * 5 + 4]);
            }
        } catch (Exception e) {
        }
    }
}

注意:<b>标签,如果没有加第一个<myfont>标签会不生效;<b>的位置可以是任何标签都可以;

Html.fromHtml()这个到底支持什么,可以看看Html中如下

private void handleStartTag(String tag, Attributes attributes) {
        if (tag.equalsIgnoreCase("br")) {
            // We don't need to handle this. TagSoup will ensure that there's a </br> for each <br>
            // so we can safely emit the linebreaks when we handle the close tag.
        } else if (tag.equalsIgnoreCase("p")) {
            startBlockElement(mSpannableStringBuilder, attributes, getMarginParagraph());
            startCssStyle(mSpannableStringBuilder, attributes);
        } else if (tag.equalsIgnoreCase("ul")) {
            startBlockElement(mSpannableStringBuilder, attributes, getMarginList());
        } else if (tag.equalsIgnoreCase("li")) {
            startLi(mSpannableStringBuilder, attributes);
        } else if (tag.equalsIgnoreCase("div")) {
            startBlockElement(mSpannableStringBuilder, attributes, getMarginDiv());
        } else if (tag.equalsIgnoreCase("span")) {
            startCssStyle(mSpannableStringBuilder, attributes);
        } else if (tag.equalsIgnoreCase("strong")) {
            start(mSpannableStringBuilder, new Bold());
        } else if (tag.equalsIgnoreCase("b")) {
            start(mSpannableStringBuilder, new Bold());
        } else if (tag.equalsIgnoreCase("em")) {
            start(mSpannableStringBuilder, new Italic());
        } else if (tag.equalsIgnoreCase("cite")) {
            start(mSpannableStringBuilder, new Italic());
        } else if (tag.equalsIgnoreCase("dfn")) {
            start(mSpannableStringBuilder, new Italic());
        } else if (tag.equalsIgnoreCase("i")) {
            start(mSpannableStringBuilder, new Italic());
        } else if (tag.equalsIgnoreCase("big")) {
            start(mSpannableStringBuilder, new Big());
        } else if (tag.equalsIgnoreCase("small")) {
            start(mSpannableStringBuilder, new Small());
        } else if (tag.equalsIgnoreCase("font")) {
            startFont(mSpannableStringBuilder, attributes);
        } else if (tag.equalsIgnoreCase("blockquote")) {
            startBlockquote(mSpannableStringBuilder, attributes);
        } else if (tag.equalsIgnoreCase("tt")) {
            start(mSpannableStringBuilder, new Monospace());
        } else if (tag.equalsIgnoreCase("a")) {
            startA(mSpannableStringBuilder, attributes);
        } else if (tag.equalsIgnoreCase("u")) {
            start(mSpannableStringBuilder, new Underline());
        } else if (tag.equalsIgnoreCase("del")) {
            start(mSpannableStringBuilder, new Strikethrough());
        } else if (tag.equalsIgnoreCase("s")) {
            start(mSpannableStringBuilder, new Strikethrough());
        } else if (tag.equalsIgnoreCase("strike")) {
            start(mSpannableStringBuilder, new Strikethrough());
        } else if (tag.equalsIgnoreCase("sup")) {
            start(mSpannableStringBuilder, new Super());
        } else if (tag.equalsIgnoreCase("sub")) {
            start(mSpannableStringBuilder, new Sub());
        } else if (tag.length() == 2 &&
                Character.toLowerCase(tag.charAt(0)) == 'h' &&
                tag.charAt(1) >= '1' && tag.charAt(1) <= '6') {
            startHeading(mSpannableStringBuilder, attributes, tag.charAt(1) - '1');
        } else if (tag.equalsIgnoreCase("img")) {
            startImg(mSpannableStringBuilder, attributes, mImageGetter);
        } else if (mTagHandler != null) {
            mTagHandler.handleTag(true, tag, mSpannableStringBuilder, mReader);
        }
    }
br 换行符  
p 定义段落  
div 定义文档中的分区或节  
strong 用于强调文本 用于强调文本
b 粗体文本 粗体文本
em 斜体显示 斜体显示
cite 斜体显示 斜体显示
dfn 斜体显示 斜体显示
i 斜体显示 斜体显示
big 大号字体
small 小号字体  
font 字体标签  
blockquote 标签定义块引用  
tt 字体显示为等宽字体  
a 超链接 百度
u 下划线 下划线
sup 上标  
sub 下标  
h1-h6 标题字体

这是标题 1

这是标题 2

这是标题 3

4-6没办法显示,这里就给出显示效果了

img 图片  

3,设置字体

要设置字体,首先要拿到这个字体库;

AssetManager mgr = getAssets();//得到AssetManager
Typeface tf = Typeface.createFromAsset(mgr, "fonts/comicSans.ttf");//根据路径得到Typeface
tv.setTypeface(tf);//设置字体

二,通过Span

TextView中有个setText(CharSequence text)方法,传参是CharSequence类型的;这个参数的子类中,有SpannableString和SpannableStringBuilder,有个共同的setSpan方法;里面就可以传入各种Span;这样就可以实现设置颜色,大小,下划线等功能;方式一中的Html内也是通过SpannableStringBuilder实现颜色,大小,加粗,下划线等功能;

2.1,设置字体颜色

SpannableString spanString = new SpannableString("床前明月光");
//构造一个改变字体颜色的Span  
ForegroundColorSpan span = new ForegroundColorSpan(Color.YELLOW);
//将这个Span应用于指定范围的字体  
spanString.setSpan(span, 1, 3, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
//设置给TextView显示出来  
tv.setText(spanString);

2.2,关于setSpan(Object what, int start, int end, int flags) 中的参数解释 

object what :对应的各种Span;

int start:表示需要设置格式的子字符串的起始索引,索引从0开始

int end:子字符串的结束索引,特效并不包括这个位置。比如如果这里数为2(即第3个字符),第3个字符不会有任何特效。

int flags:取值有如下四个

Spannable.SPAN_EXCLUSIVE_EXCLUSIVE:前后都不包括,即在指定范围的前面和后面插入新字符都不会应用新样式
Spannable.SPAN_EXCLUSIVE_INCLUSIVE:前面不包括,后面包括。即仅在范围字符的后面插入新字符时会应用新样式
Spannable.SPAN_INCLUSIVE_EXCLUSIVE:前面包括,后面不包括。
Spannable.SPAN_INCLUSIVE_INCLUSIVE:前后都包括。

2.3,各个Span

先来看看各种Span之间的继承关系,从图可以看出所有Span都集成了CharacterStyle这个抽象类;

AbsoluteSizeSpan :绝对尺寸范围,里面设置的参数为物理像素值;

相关知识

setTextColor(0xFF0000FF);  //十六进制颜色值,0xFF0000FF是int类型的数据,分组一下0x|FF|0000FF,0x是代表颜色十六进制的标记,FF是表示透明度,注意:这里0xFF0000FF必须是8个的颜色表示。  

setTextColor(Color.rgb(255, 255, 255));  //RGB 颜色值

setTextColor(Color.parseColor("#FFFFFF")); 

//还有就是使用资源文件进行设置  
setTextColor(getContext.getResources().getColor(R.color.blue));  //通过获得资源文件进行设置。根据不同的情况R.color.blue也可以是R.string.blue

 //另外还可以使用系统自带的颜色类  
setTextColor(android.graphics.Color.BLUE); 

发布了93 篇原创文章 · 获赞 50 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/ezconn/article/details/94750286