Android TextView 嵌套图片及其点击,TextView 部分文字点击,文字多颜色
1. TextView 中嵌套图片的方法
TextView textView... textView.setText("..."); textView.append(Html.fromHtml("<imgsrc='"+R.drawable.question+"'/>",imageGetter, new MTagHandler(context)));
就是在 TextView 中加入包含图片的 html 代码。
Html.fromHtml(String source, ImageGetter imageGetter, TagHandler tagHandler)
- 其中 source 里面放 html 代码,里面加入图片的资源ID(R.id.xxx)。
- ImageGetter 是一个接口,里面有抽象方法 public Drawable getDrawable(String source); 用来获取图片的 Drawable 对象(可以从网络,或 res 资源,或本地文件获取,本例中从 res 中获取)。
- TagHandler 是一个接口,用来处理 html 标签。当我们遇到一个 html 标签后,做相应的处理工作,比如点击的响应。
2. TextView 中嵌套图片的点击响应
ImageGetter 的实现:
ImageGetter imageGetter = new ImageGetter() { @Override public Drawable getDrawable(String source) { int id = Integer.parseInt(source); Drawable drawable = context.getResources().getDrawable(id); drawable.setBounds(int left, int top, int right, int bottom); return drawable; } };
TagHandler 的实现:
public class MTagHandler implements TagHandler { private int sIndex = 0; private int eIndex = 0; private final Context mContext; public MTagHandler(Context context) { mContext = context; } public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) { // TODO Auto-generated method stub if (tag.toLowerCase().equals("img")) { if (opening) { sIndex = output.length(); } else { eIndex = output.length(); output.setSpan(new MSpan(), sIndex, eIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } } } private class MSpan extends ClickableSpan implements OnClickListener { @Override public void onClick(View widget) { // TODO Auto-generated method stub Log.e("test", "aaaaaaaaaaaa"); Toast.makeText(context, "sdfdsfsdfdsf", 1000).show(); } } }
碰到 img 标签后做 onClick 里的响应处理。
最后,非常重要的一件事,就是要给 TextView 做个设置,否则点击不会相应。
textView.setMovementMethod(LinkMovementMethod.getInstance());
3. TextView 中部分文字的点击相应
这里需要使用 SpannableString(不可变) 或 SpannableStringBuilder(可变)。
首先,创建一个 SpannbleString:
SpannableString spannableString = new SpannableString("xxxx");
spannableString.setSpan(Object what, int start, int end, int flags);
Object what 这里放一个 ClickableSpan,并实现它的 onClick 方法用于点击相应。
int start,int end 定义字符串的区间。
int flags 表示样式。在 Spanned 类中有很多参数可供使用。常用的是 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
spannableString.setSpan(new ClickableSpan() { @Override public void onClick(View widget) { // TODO Auto-generated method stub // 要做的事写在这里 } },0, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
然后把 TextView 的文字内容设置为 SpannbleString:
textView.setText(spannableString);
最后,同样的,非常重要的一件事,就是要给 TextView 做个设置,否则点击不会相应。
textView.setMovementMethod(LinkMovementMethod.getInstance());
4. TextView 中改变部分文字的颜色或背景颜色等
添加图片(不需要点击响应的话)可以用 ImageSpan span = new ImageSpan(drawable, ImageSpan.ALIGN_BASELINE);
改变部分文字颜色或背景:
mTextView = (TextView)findViewById(R.id.test); SpannableString s = new SpannableString(mTextView.getText()); s.setSpan(new BackgroundColorSpan(Color.RED), 0, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); //红色高亮 s.setSpan(new UnderlineSpan(), 15, 18,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); //下划线
s.setSpan(new ForegroundColorSpan(Color.RED), 0, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); //字体红色
s.setSpan(new StyleSpan(android.graphics.Typeface.BOLD_ITALIC), 2, 5, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); //斜体加黑 mTextView.setText(s);
一篇不错的写 SpannbleString 的文章:
http://ezfantasy.iteye.com/blog/1468631
http://www.apkbus.com/forum.php?mod=viewthread&tid=18983
5. TextView 中遇到的一个有趣的Bug
在一次实际应用中。我做了一个答题的程序。答了的题的标题前加上一个对号表示这个题回答过了。
我开始是这样做的:
SpannableString s = new SpannableString("✔ " + textTitle.getText()); s.setSpan(new ForegroundColorSpan(context.getResources().getColor(R.color.custom_theme_color_green)), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); textTitle.setText(s);
我另外有一个函数用来删除标题前的对号用来表示此题回答了之后又被取消了。
真正出现的问题是:
我的 TextView 里加入过一个内嵌的小图片按钮,详情见最上面。然后当我添加/删除 小对号 "✔ " 之后,我的图片按钮突然不见了。
原因:
带有 Span 的 TextView 的文字内容是 CharSequence 类型。为了让里面包含的 Span 不丢失,不可以对它进行类型转换。所以当我们进行添加对号时,必须用 TextView 的 append() 函数。像上面代码写的,文字内容被转换为 SpannableString 了,然后 Span 丢失了。为什么会这样呢,看了一下 SpannableString 的构造函数的源码才知道,new SpannableString(CharSequence source) 的时候,里面的 CharSequence 被执行了 source.toString(); 而 Span 就是这么丢的。
那么解决方法呢:
- 添加对号:
SpannableString s = new SpannableString("✔ "); s.setSpan(new ForegroundColorSpan(context.getResources().getColor(R.color.custom_theme_color_green)), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); CharSequence c = textTitle.getText(); textTitle.setText(s); textTitle.append(c);
- 删除对号:
textTitle.setText(textTitle.getText().subSequence(2, textTitle.getText().length()));