Textview加入Intent、表情,点击跳转Activity
来源:互联网 发布:javascript 表单 编辑:程序博客网 时间:2024/04/29 04:50
看来TextView是支持链接跳转的,不过做Android开发的应该都知道,android的View载体是Activity,能不能支持activity跳转呢,很遗憾,不支持。
不过无所谓,Android很有爱,开源的,理解了原理后我们自己去做,这也是我写本篇文章的主要目的,"授之以鱼,不如授之以渔",希望大家在遇到相似问题时能像我这样去分析源码,然后找出解决办法(或者大家可以提出更好的方法),另外,文中如有不妥的地方,也欢迎大家批评指正。先上效果图:点击左边的链接后跳转到右边。
现在我们开始开发吧!第一步,研究相关的源代码吧。通过跟踪TextView的源码,我们发现TextView支持的链接是由android.text.style.URLSpan这个类实现的,它重写了一个onClick方法:
- public void onClick(View widget) {
- Uri uri = Uri.parse(getURL());
- Context context = widget.getContext();
- Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
- context.startActivity(intent);
- }
public void onClick(View widget) { Uri uri = Uri.parse(getURL()); Context context = widget.getContext(); Intent intent = new Intent(Intent.ACTION_VIEW, uri); intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()); context.startActivity(intent); }
大家看到了吧startActivity,多么熟悉的方法。既然它能实现,为什么我们不能呢,答案是可以的。我们接着跟踪代码,可以看到URLSpan其实继承的是android.text.style.ClickableSpan,我们来看一下他的源码:
- /**
- * Performs the click action associated with this span.
- */
- public abstract void onClick(View widget);
- /**
- * Makes the text underlined and in the link color.
- */
- @Override
- public void updateDrawState(TextPaint ds) {
- ds.setColor(ds.linkColor);
- ds.setUnderlineText(true);
- }
- }
public abstract class ClickableSpan extends CharacterStyle implements UpdateAppearance { /** * Performs the click action associated with this span. */ public abstract void onClick(View widget); /** * Makes the text underlined and in the link color. */ @Override public void updateDrawState(TextPaint ds) { ds.setColor(ds.linkColor); ds.setUnderlineText(true); }}
是不是有点眉目了,我们直接继承这个类,重写他的方法不就可以了吗?大胆假设,小心求证,我们新建一个类:
- import android.content.Intent;
- import android.text.TextPaint;
- import android.text.style.ClickableSpan;
- import android.view.View;
- /**
- * If an object of this type is attached to the text of a TextView with a
- * movement method of LinkMovementMethod, the affected spans of text can be
- * selected. If clicked, the {@link #onClick} method will be called.
- *
- * @author 张宁
- */
- public class MyClickableSpan extends ClickableSpan {
- int color = -1;
- private Context context;
- private Intent intent;
- public MyClickableSpan(Context context, Intent intent) {
- this(-1, context, intent);
- }
- /**
- * constructor
- * @param color the link color
- * @param context
- * @param intent
- */
- public MyClickableSpan(int color, Context context, Intent intent) {
- if (color!=-1) {
- this.color = color;
- }
- this.context = context;
- this.intent = intent;
- }
- /**
- * Performs the click action associated with this span.
- */
- public void onClick(View widget){
- context.startActivity(intent);
- };
- /**
- * Makes the text without underline.
- */
- @Override
- public void updateDrawState(TextPaint ds) {
- if (color == -1) {
- ds.setColor(ds.linkColor);
- } else {
- ds.setColor(color);
- }
- ds.setUnderlineText(false);
- }
- }
import android.content.Context;import android.content.Intent;import android.text.TextPaint;import android.text.style.ClickableSpan;import android.view.View;/** * If an object of this type is attached to the text of a TextView with a * movement method of LinkMovementMethod, the affected spans of text can be * selected. If clicked, the {@link #onClick} method will be called. * * @author 张宁 */public class MyClickableSpan extends ClickableSpan {int color = -1;private Context context;private Intent intent;public MyClickableSpan(Context context, Intent intent) {this(-1, context, intent);}/** * constructor * @param color the link color * @param context * @param intent */public MyClickableSpan(int color, Context context, Intent intent) {if (color!=-1) {this.color = color;}this.context = context;this.intent = intent;}/** * Performs the click action associated with this span. */public void onClick(View widget){context.startActivity(intent);};/** * Makes the text without underline. */@Overridepublic void updateDrawState(TextPaint ds) {if (color == -1) {ds.setColor(ds.linkColor);} else {ds.setColor(color);}ds.setUnderlineText(false);}}
在这个类里,我们重写了onClick事件,实现了Activity的跳转,并且去掉了下划线。Ok,第一个目的就达到了,下面我们来看一下如何在TextView里加入表情。
这个就比较复杂了,因为TextView只能在其上下左右方向加入图片,是由Drawables这个类实现的,而我们想要的效果是在中间也可以插入,看来这次TextView插入图片源码帮不了我们了。不过我们可以去android.text这个包里去找别的类,大家可以看到在这个包里有一个Html类,做过web开发的应该可以想到什么吧?在文章开头已经提到了Html的<img>标签可以插入图片,那这个类是否提供这个功能呢?带着这个疑问我们可以进去看看,其中有个接口:
- /**
- * Retrieves images for HTML <img> tags.
- */
- public static interface ImageGetter {
- /**
- * This methos is called when the HTML parser encounters an
- * <img> tag. The <code>source</code> argument is the
- * string from the "src" attribute; the return value should be
- * a Drawable representation of the image or <code>null</code>
- * for a generic replacement image. Make sure you call
- * setBounds() on your Drawable if it doesn't already have
- * its bounds set.
- */
- public Drawable getDrawable(String source);
- }
/** * Retrieves images for HTML <img> tags. */ public static interface ImageGetter { /** * This methos is called when the HTML parser encounters an * <img> tag. The <code>source</code> argument is the * string from the "src" attribute; the return value should be * a Drawable representation of the image or <code>null</code> * for a generic replacement image. Make sure you call * setBounds() on your Drawable if it doesn't already have * its bounds set. */ public Drawable getDrawable(String source); }
看到<code>source</code>这个没,熟悉吧,结合URLSpan的用法,我们是否可以配合Spanned实现一个
ImageSpan呢?OK,上代码:
- import java.util.Map;
- import java.util.Set;
- import android.content.Context;
- import android.graphics.drawable.Drawable;
- import android.text.Html;
- import android.text.Spanned;
- import android.text.Html.ImageGetter;
- /**
- * this is a class which defining a spanned with image
- * @author 张宁
- *
- */
- public class ImageSpan {
- /**
- * the map of face.
- */
- private Map<String, String> faceMap;
- private Context context;
- public ImageSpan(Context context, Map<String, String> faceMap){
- this.context = context;
- this.faceMap = faceMap;
- }
- /**
- * get the image by the given key
- */
- private ImageGetter imageGetter = new Html.ImageGetter() {
- @Override
- public Drawable getDrawable(String source) {
- Drawable drawable = null;
- String sourceName = context.getPackageName() + ":drawable/"
- + source;
- int id = context.getResources().getIdentifier(sourceName, null, null);
- if (id != 0) {
- drawable = context.getResources().getDrawable(id);
- if (drawable != null) {
- drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
- drawable.getIntrinsicHeight());
- }
- }
- return drawable;
- }
- };
- /**
- * return a {@link Spanned} with image
- * @param text
- * @return
- */
- public Spanned getImageSpan(CharSequence text){
- String cs = text.toString();
- if (faceMap != null) {
- Set<String> keys = faceMap.keySet();
- for (String key : keys) {
- if (cs.contains(key)) {
- cs = cs.replace(key, "<img src='" + faceMap.get(key) + "'>");
- }
- }
- }
- return Html.fromHtml(cs, imageGetter, null);
- }
- }
import java.util.Map;import java.util.Set;import android.content.Context;import android.graphics.drawable.Drawable;import android.text.Html;import android.text.Spanned;import android.text.Html.ImageGetter;/** * this is a class which defining a spanned with image * @author 张宁 * */public class ImageSpan {/** * the map of face. */private Map<String, String> faceMap;private Context context;public ImageSpan(Context context, Map<String, String> faceMap){this.context = context;this.faceMap = faceMap;} /** * get the image by the given key */private ImageGetter imageGetter = new Html.ImageGetter() {@Overridepublic Drawable getDrawable(String source) {Drawable drawable = null;String sourceName = context.getPackageName() + ":drawable/"+ source;int id = context.getResources().getIdentifier(sourceName, null, null);if (id != 0) {drawable = context.getResources().getDrawable(id);if (drawable != null) {drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight());}}return drawable;}};/** * return a {@link Spanned} with image * @param text * @return */public Spanned getImageSpan(CharSequence text){String cs = text.toString();if (faceMap != null) {Set<String> keys = faceMap.keySet();for (String key : keys) {if (cs.contains(key)) {cs = cs.replace(key, "<img src='" + faceMap.get(key) + "'>");}}}return Html.fromHtml(cs, imageGetter, null);}}
到目前为止可以说关键代码都已经实现了,但是会有人问,我该如何使用这两个类呢?下面,我们在实现一个工具类来封装这两个类的方法,以方便调用:
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import android.content.Context;
- import android.content.Intent;
- import android.text.SpannableStringBuilder;
- import android.text.Spanned;
- import android.text.TextUtils;
- import android.text.method.LinkMovementMethod;
- import android.widget.EditText;
- import android.widget.TextView;
- /**
- * TextView with intent that can redirect to a new activity
- *
- * @author 张宁
- *
- */
- public class CustomTextView {
- private static Map<String, String> faceMap;
- static {
- faceMap = new HashMap<String, String>();
- faceMap.put("[哭]", "face_1");
- faceMap.put("[怒]", "face_2");
- }
- /**
- * make textview a clickable textview<br>
- * Note: make true the order of textList and intentList are mapped
- *
- * @param context
- * @param textView
- * @param textList
- * the text should be set to this textview,not null
- * @param intentList
- * the intent map to the text, if the text have no intent mapped
- * to, please set a null value.Or it will happen some unknown
- * error.<br>
- * not null
- */
- public static void setClickableTextView(Context context, TextView textView,
- List<String> textList, List<Intent> intentList) {
- if (textList == null || intentList == null) {
- return;
- }
- SpannableStringBuilder builder = new SpannableStringBuilder();
- int end = -1, length = -1;
- int size = textList.size();
- Intent intent;
- for (int i = 0; i < size; i++) {
- String text = textList.get(i);
- if (TextUtils.isEmpty(text)) {
- continue;
- }
- builder.append(textList.get(i));
- if ((intent = intentList.get(i)) != null) {
- end = builder.length();
- length = textList.get(i).length();
- builder.setSpan(getClickableSpan(context, intent),
- end - length, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- builder.append(" ");
- }
- textView.setText(builder);
- textView.setFocusable(true);
- textView.setMovementMethod(LinkMovementMethod.getInstance());
- }
- /**
- * make textview a clickable textview<br>
- * Note: make true the order of textList and intentList are mapped
- * @param context
- * @param textView
- * @param text
- * @param intent
- */
- public static void setClickableTextView(Context context, TextView textView,
- String text, Intent intent) {
- SpannableStringBuilder builder = new SpannableStringBuilder(text);
- builder.setSpan(getClickableSpan(context, intent), 0, text.length(),
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- textView.setText(builder);
- textView.setMovementMethod(LinkMovementMethod.getInstance());
- }
- /**
- * make TextView a View with image at any index
- * @param context
- * @param textView
- * @param textList
- */
- public static void setImgTextView(Context context, TextView textView,
- List<String> textList) {
- StringBuilder builder = new StringBuilder();
- for (int i = 0; i < textList.size(); i++) {
- builder.append(textList.get(i)).append(" ");
- }
- setImgTextView(context, textView, builder.toString());
- }
- /**
- * make TextView a View with image at any index
- * @param context
- * @param textView
- * @param text
- */
- public static void setImgTextView(Context context, TextView textView,
- String text) {
- ImageSpan imageSpan = new ImageSpan(context, faceMap);
- Spanned spanned = imageSpan.getImageSpan(text);
- textView.setText(spanned);
- }
- /**
- * make EditText a View with image at any index
- * @param context
- * @param EditText
- * @param text
- */
- public static void setImgTextView(Context context, EditText editText,
- String text) {
- ImageSpan imageSpan = new ImageSpan(context, faceMap);
- Spanned spanned = imageSpan.getImageSpan(text);
- editText.setText(spanned);
- }
- /**
- * return a custom ClickableSpan
- *
- * @param context
- * @param intent
- * @return
- */
- public static MyClickableSpan getClickableSpan(Context context,
- Intent intent) {
- return new MyClickableSpan(context, intent);
- }
- /**
- * make textview a clickable textview with image<br>
- * Note: make true the order of textList and intentList are mapped
- *
- * @param context
- * not null
- * @param haveImg
- * whether this is image in the text,not null
- * @param textView
- * not null
- * @param textList
- * the text should be set to this textview,not null
- * @param intentList
- * the intent map to the text, if the text have no intent mapped
- * to, please set a null value.Or it will happen some unknown
- * error.<br>
- * allow null
- */
- public static void setCustomText(Context context, Boolean haveImg,
- TextView textView, List<String> textList, List<Intent> intentList) {
- SpannableStringBuilder builder = new SpannableStringBuilder();
- int end = -1, length = -1;
- if (intentList != null) {
- int size = textList.size();
- Intent intent;
- for (int i = 0; i < size; i++) {
- String text = textList.get(i);
- if (TextUtils.isEmpty(text)) {
- continue;
- }
- builder.append(textList.get(i));
- if ((intent = intentList.get(i)) != null) {
- end = builder.length();
- length = textList.get(i).length();
- builder.setSpan(getClickableSpan(context, intent), end
- - length, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- builder.append(" ");
- }
- } else {
- for (String text : textList) {
- builder.append(text).append(" ");
- }
- }
- if (haveImg) {
- ImageSpan imageSpan = new ImageSpan(context, faceMap);
- Spanned spanned = imageSpan.getImageSpan(builder);
- textView.setText(spanned);
- } else {
- textView.setText(builder);
- }
- textView.setMovementMethod(LinkMovementMethod.getInstance());
- }
- }
import java.util.HashMap;import java.util.List;import java.util.Map;import android.content.Context;import android.content.Intent;import android.text.SpannableStringBuilder;import android.text.Spanned;import android.text.TextUtils;import android.text.method.LinkMovementMethod;import android.widget.EditText;import android.widget.TextView;/** * TextView with intent that can redirect to a new activity * * @author 张宁 * */public class CustomTextView {private static Map<String, String> faceMap;static {faceMap = new HashMap<String, String>();faceMap.put("[哭]", "face_1");faceMap.put("[怒]", "face_2");}/** * make textview a clickable textview<br> * Note: make true the order of textList and intentList are mapped * * @param context * @param textView * @param textList * the text should be set to this textview,not null * @param intentList * the intent map to the text, if the text have no intent mapped * to, please set a null value.Or it will happen some unknown * error.<br> * not null */public static void setClickableTextView(Context context, TextView textView,List<String> textList, List<Intent> intentList) {if (textList == null || intentList == null) {return;}SpannableStringBuilder builder = new SpannableStringBuilder();int end = -1, length = -1;int size = textList.size();Intent intent;for (int i = 0; i < size; i++) {String text = textList.get(i);if (TextUtils.isEmpty(text)) {continue;}builder.append(textList.get(i));if ((intent = intentList.get(i)) != null) {end = builder.length();length = textList.get(i).length();builder.setSpan(getClickableSpan(context, intent),end - length, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);}builder.append(" ");}textView.setText(builder);textView.setFocusable(true);textView.setMovementMethod(LinkMovementMethod.getInstance());}/** * make textview a clickable textview<br> * Note: make true the order of textList and intentList are mapped * @param context * @param textView * @param text * @param intent */public static void setClickableTextView(Context context, TextView textView,String text, Intent intent) {SpannableStringBuilder builder = new SpannableStringBuilder(text);builder.setSpan(getClickableSpan(context, intent), 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);textView.setText(builder);textView.setMovementMethod(LinkMovementMethod.getInstance());}/** * make TextView a View with image at any index * @param context * @param textView * @param textList */public static void setImgTextView(Context context, TextView textView,List<String> textList) {StringBuilder builder = new StringBuilder();for (int i = 0; i < textList.size(); i++) {builder.append(textList.get(i)).append(" ");}setImgTextView(context, textView, builder.toString());}/** * make TextView a View with image at any index * @param context * @param textView * @param text */public static void setImgTextView(Context context, TextView textView,String text) {ImageSpan imageSpan = new ImageSpan(context, faceMap);Spanned spanned = imageSpan.getImageSpan(text);textView.setText(spanned);}/** * make EditText a View with image at any index * @param context * @param EditText * @param text */public static void setImgTextView(Context context, EditText editText,String text) {ImageSpan imageSpan = new ImageSpan(context, faceMap);Spanned spanned = imageSpan.getImageSpan(text);editText.setText(spanned);}/** * return a custom ClickableSpan * * @param context * @param intent * @return */public static MyClickableSpan getClickableSpan(Context context,Intent intent) {return new MyClickableSpan(context, intent);}/** * make textview a clickable textview with image<br> * Note: make true the order of textList and intentList are mapped * * @param context * not null * @param haveImg * whether this is image in the text,not null * @param textView * not null * @param textList * the text should be set to this textview,not null * @param intentList * the intent map to the text, if the text have no intent mapped * to, please set a null value.Or it will happen some unknown * error.<br> * allow null */public static void setCustomText(Context context, Boolean haveImg,TextView textView, List<String> textList, List<Intent> intentList) {SpannableStringBuilder builder = new SpannableStringBuilder();int end = -1, length = -1;if (intentList != null) {int size = textList.size();Intent intent;for (int i = 0; i < size; i++) {String text = textList.get(i);if (TextUtils.isEmpty(text)) {continue;}builder.append(textList.get(i));if ((intent = intentList.get(i)) != null) {end = builder.length();length = textList.get(i).length();builder.setSpan(getClickableSpan(context, intent), end- length, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);}builder.append(" ");}} else {for (String text : textList) {builder.append(text).append(" ");}}if (haveImg) {ImageSpan imageSpan = new ImageSpan(context, faceMap);Spanned spanned = imageSpan.getImageSpan(builder);textView.setText(spanned);} else {textView.setText(builder);}textView.setMovementMethod(LinkMovementMethod.getInstance());}}
有了这个类,我们就可以方便的实现在TextView中插入Intent和表情了,甚至不用管底层是怎样实现的,也降低了代码的耦合度。但是又回到我写这篇文章的目的:希望大家能得到“渔”而不仅仅是“鱼”。
Ok,任务完成。源码奉上。
- Textview加入Intent、表情,点击跳转Activity
- Textview加入Intent、表情,点击跳转Activity
- Intent 跳转Activity
- intent 跳转activity无效
- Intent 实现Activity跳转
- Activity的跳转Intent
- activity用intent跳转
- Intent实现activity跳转
- Activity 跳转之Intent
- Intent实现Activity跳转
- TextView识别网址点击跳转
- preferenceScreen 利用intent跳转activity
- 使用Intent实现Activity跳转
- Intent实现Activity的跳转
- 隐式Intent实现Activity跳转
- Android使用ListView构造复杂界面,响应点击事件,通过Intent跳转activity
- Activity交互---Activity跳转(Intent实现)
- Activity: TextView,EditText,Button,Intent快速入门
- IE不支持option的display样式,只能使用remove和add
- Java中几种输出数组的for循环,以及循环中使用标签(非goto)
- Android:如何在ListView中嵌套ListView (如何实现二级目录结构?)的两种实现方式
- 题目39:特殊乘法
- 怎么区分电脑是32位还是64位有什么不一样
- Textview加入Intent、表情,点击跳转Activity
- GridView控件的一些知识
- 题目40:反序数
- 我的JavaforAndroid学习之路-堆栈实现的四则运算
- 实现选择下拉列表中时间而显示图片后台代码
- zoj3430
- Android 挂载 NFS
- vc开机自启动代码
- 题目41:对称平方数