目录
一,通过Html实现
1,例如实现如下效果
2,为一段文字中某些字单独设置字体大小
3,设置字体
二,通过Span
相关知识
前言
有时候一个TextView显示很多文字,所有文字颜色,字体,大小不统一;这个时候就需要单独设置某些字;
1.1,为一段文字中某些字单独设置一种颜色
通过Html.fromHtml(String source)方法实现
String str1 = "微信扫码关注公众号,立即开始";
textView.setText(Html.fromHtml(str1));
注意:fromHtml(String source)在PI Level 24以上已废弃,API Level 24或以上的设备则使用2个参数的方法即可。fromHtml(String source, int flags)
String str1 = "微信扫码关注公众号,立即开始";
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 = "床前明月光,
";
String text2 = "疑是地上霜。
";
String text3 = "举头望明月,
";
String text4 = "低头思故乡。
";
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.1,下面是在xml中设置了android:textSize="30sp"属性,然后java代码中设置了和
TextView tv = findViewById(R.id.tv);
String text1 = "床前明月光,
";
String text2 = "疑是地上霜。
";
String text3 = "举头望明月,
";
String text4 = "低头思故乡。
";
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);
注意:和标签,设置的大小都是在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 = "" + str + "
"
+ "" + str1 + " ";
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 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) {
}
}
}
注意:标签,如果没有加第一个
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 for each
// 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这是标题 34-6没办法显示,这里就给出显示效果了 |
img | 图片 |
要设置字体,首先要拿到这个字体库;
AssetManager mgr = getAssets();//得到AssetManager
Typeface tf = Typeface.createFromAsset(mgr, "fonts/comicSans.ttf");//根据路径得到Typeface
tv.setTypeface(tf);//设置字体
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);