不废话,先上图
一、字体字号背景色设置
1.1 N(6.0) 以上的系统
在Html.fromHtml(getTest(), Html.FROM_HTML_MODE_COMPACT)
添加Html.FROM_HTML_MODE_COMPACT
就可以了
1.2 N(6.0) 以下的系统
需要自定义Html.TagHandler
来实现字号、背景色等的设置
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) { 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(color)) { output.setSpan(new ForegroundColorSpan(Color.parseColor(color)), startIndex, endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } if (!TextUtils.isEmpty(size)) { output.setSpan(new AbsoluteSizeSpan(Integer.parseInt(size)), startIndex, endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } }
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) { e.printStackTrace(); } } }
|
二、图片加载
自定义Html.ImageGetter
来实现
2.1 创建DrawableWrapper
因为ImageGetter接口返回的Drawable是不可变的,但是在加载网络图片完成后需要更新图片,因此在Drawable外加一个Wrapper
class DrawableWrapper extends BitmapDrawable { private Drawable drawable;
DrawableWrapper() { }
@Override public void draw(Canvas canvas) { if (drawable != null) drawable.draw(canvas); }
public Drawable getDrawable() { return drawable; }
public void setDrawable(Drawable drawable) { this.drawable = drawable; } }
|
2.2 创建ImageGetter
我这采用的是Volley
来加载图片,你页可以使用其它框架来加载,原理都一样。
在这有几个坑需要注意下:
1、为了能让图片正常显示,你需要设置DrawableWrapper的高度和宽度
2、如果你使用了默认图,你需要设置默认图的高和宽
3、加载完成图片后,你需要重新设置TextView的高度,否则内容将不能完全显示出来
4、设置完成高宽后,还需要使用postInvalidate
来刷新界面,否则图片显示不出来
private class IamegGetter implements Html.ImageGetter {
@Override public Drawable getDrawable(final String source) { final DrawableWrapper imgDrawable = new DrawableWrapper();
Drawable dfDrawable = getResources().getDrawable(R.mipmap.ic_launcher); Rect dfRect = new Rect(0, 0, tv.getMeasuredWidth(), tv.getMeasuredWidth() * dfDrawable.getIntrinsicHeight() / dfDrawable.getIntrinsicWidth()); dfDrawable.setBounds(dfRect); imgDrawable.setBounds(dfRect); imgDrawable.setDrawable(dfDrawable);
RequestQueue mQueue = Volley.newRequestQueue(MainActivity.this); ImageRequest imageRequest = new ImageRequest( source, new Response.Listener<Bitmap>() { @Override public void onResponse(Bitmap response) { Log.d("TAG", response.getWidth() + "/" + response.getHeight()); int tvWidth = tv.getMeasuredWidth();
Drawable bd = new BitmapDrawable(response); Rect rect = new Rect(0, 0, tvWidth, tvWidth * response.getHeight() / response.getWidth()); bd.setBounds(rect); imgDrawable.setBounds(rect); imgDrawable.setDrawable(bd);
int tvH = tv.getHeight() + rect.bottom; tv.setMaxHeight(tvH); tv.postInvalidate(); } }, 0, 0, Bitmap.Config.RGB_565, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Drawable drawable = getResources().getDrawable(R.mipmap.ic_launcher); imgDrawable.setDrawable(drawable); tv.postInvalidate(); Log.d("tAG", "加载失败"); } }); mQueue.add(imageRequest); return imgDrawable; } }
|
2.3 获取image点击
有的时候,我们需要获取用户点击的是哪个图片,可以这样做
1、创建对象保存图片排序和内容
List<String> imgSource = new ArrayList<>(); ImageSpan[] imags;
|
2、获取图片排序和内容
imags = clickableHtmlBuilder.getSpans(0, spanned.length(), ImageSpan.class); for (ImageSpan span : imags) { imgSource.add(span.getSource()); setImageClickAction(clickableHtmlBuilder, span); } tv.setText(clickableHtmlBuilder); tv.setMovementMethod(LinkMovementMethod.getInstance());
|
3、设置图片的点击事件
private void setImageClickAction(final SpannableStringBuilder clickableHtmlBuilder, final ImageSpan imageSpan) { int start = clickableHtmlBuilder.getSpanStart(imageSpan); int end = clickableHtmlBuilder.getSpanEnd(imageSpan); int flags = clickableHtmlBuilder.getSpanFlags(imageSpan);
ClickableSpan clickableSpan = new ClickableSpan() {
@Override public void onClick(View view) { int postion = imgSource.indexOf(imageSpan.getSource()); Log.d("TAG", "postion = " + postion + ", id = " + view.getId()); }
}; clickableHtmlBuilder.setSpan(clickableSpan, start, end, flags); }
|
三、超链接
3.1 使用浏览器打开
textview 设置以下方法便可
tv.setMovementMethod(LinkMovementMethod.getInstance());
|
3.2 拦截url点击,内部webview打开
有时,我们需要使用自己的Webview打开url,这时就需要下面几个步骤来实现
1、在textview的布局文件里面加入这个属性
2、创建url响应方法
private void setLinkClickAction(final SpannableStringBuilder clickableHtmlBuilder, final URLSpan urlSpan) { int start = clickableHtmlBuilder.getSpanStart(urlSpan); int end = clickableHtmlBuilder.getSpanEnd(urlSpan); int flags = clickableHtmlBuilder.getSpanFlags(urlSpan); ClickableSpan clickableSpan = new ClickableSpan() {
@Override public void updateDrawState(TextPaint ds) { super.updateDrawState(ds); ds.setUnderlineText(false); ds.setColor(Color.parseColor("#00B2EE")); }
@Override public void onClick(View view) { String url = urlSpan.getURL(); Toast.makeText(MainActivity.this, url, Toast.LENGTH_SHORT).show(); }
}; clickableHtmlBuilder.setSpan(clickableSpan, start, end, flags); }
|
3、解析url
Spanned spanned = Html.fromHtml(source); SpannableStringBuilder clickableHtmlBuilder = new SpannableStringBuilder(spanned); URLSpan[] urls = clickableHtmlBuilder.getSpans(0, spanned.length(), URLSpan.class); for (final URLSpan span : urls) { setLinkClickasetLinkClickActionble(clickableHtmlBuilder, span); }
tv.setText(clickableHtmlBuilder); tv.setMovementMethod(LinkMovementMethod.getInstance());
|