`
zhangning290
  • 浏览: 11127 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Textview加入Intent、表情,点击跳转Activity

阅读更多

      (第二届 Google 暑期大学生博客分享大赛 - 2011 Android 成长篇

      做过web开发的人应该都知道,在HTML里支持<a>标签在文本里插入一个链接,点击后跳转;并且有<img>标签可以插入图片。Android开发是否也支持呢?带着这个疑问,我们去APIDemos探索一下。OK,在com.example.android.apis.text.link这个类里,官方演示了TextView支持的一些链接,上个图:


 

      看来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);
    }

      大家看到了吧startActivity,多么熟悉的方法。既然它能实现,为什么我们不能呢,答案是可以的。我们接着跟踪代码,可以看到URLSpan其实继承的是android.text.style.ClickableSpan,我们来看一下他的源码:

 

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.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.
	 */
	@Override
	public 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 &lt;img&gt; tags.
     */
    public static interface ImageGetter {
        /**
         * This methos is called when the HTML parser encounters an
         * &lt;img&gt; 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.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,任务完成。源码奉上。

注:原创作品,转载请标明出处:

 

 http://zhangning290.iteye.com/blog/1134286

 

 

  • 大小: 17.6 KB
  • 大小: 15.9 KB
  • 大小: 34.9 KB
分享到:
评论
3 楼 Evilover3 2014-03-12  
确实学习到不少
2 楼 hgl718075399 2012-07-06  
相当不错哦!!!!!
1 楼 lenomon 2012-04-07  

相关推荐

    Android TextView中文本点击文字跳转 (代码简单)

    在web页面中,有a标签的超链接实现跳转,同样在Android当中,用TextView控件来显示文字,实现它的事件来跳转。 用过微博Android手机端的朋友的都知道微博正文有时有一些高亮显示的文本,如话题、提到的人等等,当...

    Android实验报告—网络通信.doc

    学会利用Inten t进行Activity的跳转,以及链接网页信息;学会利用Intent将其他Activity的信息返回 到Activity中的方法。体会Activity间通信的过程。 实验要求: 编程实现下述功能:主界面上有一个"登录"按钮和"链接...

    Android应用开发I实验指导书.doc

    Intent跳转。 【实验环境】 硬件环境:笔记本 软件环境:Eclipse+SDK+JDK 编程语言:Java 【相关知识】 界面布局、EditText、TextView、Button、CheckBox等控件使用。 【实验内容】 实现类似下图的效果:界面布局...

    星座说明书

    通过创建线程对象,然后自动调用了run()方法,到达设置的时间时自动跳转启动进入下一个Activity界面。  3.1.2程序 //定义欢迎界面类 public class LaunchActivity extends Activity{ @Override protected void ...

    Android中activity处理返回结果的实现方式

    大家在网上购物时都有这样一个体验,在确认订单选择收货人以及地址时,会跳转页面到我们存入网站内的所有收货信息(包含收货地址,收货人)的界面供我们选择,一旦我们点击其中某一条信息,则会自动跳转到订单提交...

    应用启动页自定义跳转计时器View Demo

    应用启动页自定义跳转计时器View Demo: CircleTextProgressbar.java: package com.demo.startpageskiptimerdemo.widget; import android.content.Context; import android.content.res.ColorStateList; import ...

    Android平台搭建与简单应用设计

    创建activity并利用Intent实现跳转 二.实验内容 下载并安装Android studio开发环境。 创建一个简单的项目,输出“你好啊,这是我的第一个安卓项目!” 创建项目,使用表格布局管理器放置组件,界面如下图所示。 /...

    开发一款任意APP-开发一款任意APP需要的类库以及多渠道打包命名框架 如需学习用法详见旧版本:https://github.com/geeklx/jiuzhidao_xinjiagou.zip

     mContext.startActivity(intent);  }  }).create());  2.ClickableMovementMethod:给textview设置超链接  ((TextView) helper.getView(R.id.brademo1_tweetText)).setMovementMethod...

    Notification消息通知 自定义消息通知内容布局

    点击界面中心的“点击发送消息”TextView控件,模拟发送通知消息,通知栏接收消息,点击几次则发送几次,点击通知栏消息,跳转到详情界面。 1.activity_main.xml: &lt;LinearLayout xmlns:android=...

    android项目实训报告.doc

    " "目 "我的项目有七个页面,实现了六次Activity跳转,用到了TextView,Edit" " "Text,Button等组件,添加了菜单功能和弹出对话框,使用Intent传递数" "分 "据和接收信息。 " " " " "析 " " " " " " " " " " " " " ...

    android开发入门与实战(下)

    7.5 Android应用的灵魂——Intent和Activity介绍与实例 7.5.1 实例操作演示 7.5.2 实例编程实现 7.6 用好列表,做好程序——列表(ListView)介绍与实例 7.6.1 实例程序演示 7.6.2 实例编程实现 7.7 友好地互动交流...

    android开发入门与实战(上)

    7.5 Android应用的灵魂——Intent和Activity介绍与实例 7.5.1 实例操作演示 7.5.2 实例编程实现 7.6 用好列表,做好程序——列表(ListView)介绍与实例 7.6.1 实例程序演示 7.6.2 实例编程实现 7.7 友好地互动交流...

    Android 开发技巧

    2.1.4、Activity 的跳转(含Bundle传值) 17 2.1.5.Actvity 堆栈 18 2.1.6、Intent对象调用Activity实例 19 2.1.7、Activity透明 21 2.1.8、一次性关闭所有的Activity 22 2.1.9、PreferenceActivity 用法 22 2.1.10...

    安卓记事本

    * 2,ListView的点击事件,跳转到第二个界面,用来修改数据 * 4,menu里的退出事件,用来退出程序 * 5,menu里的新建事件,用来新建便签 * 6,对返回按钮监听退出程序 */ public class MainActivity extends ...

    Android开发资料合集-World版!

    2.1.4、Activity 的跳转(含Bundle传值) 17 2.1.5.Actvity 堆栈 18 2.1.6、Intent对象调用Activity实例 19 2.1.7、Activity透明 21 2.1.8、一次性关闭所有的Activity 22 2.1.9、PreferenceActivity 用法 22 2.1.10...

    Google Android开发入门与实战的代码

    7.5 Android应用的灵魂——Intent和Activity介绍与实例 106 7.5.1 实例操作演示 106 7.5.2 实例编程实现 106 7.6 用好列表,做好程序——列表(ListView)介绍与实例 111 7.6.1 实例程序演示 111 7.6.2...

    Android开发案例驱动教程 配套代码

    9.3 多Activity之间跳转 188 9.3.1 多个Activity之间数据传递 189 9.3.2 跳转与返回 192 9.3.3 任务与标志 196 9.4 Android系统内置Intent 199 本章小结 201 第10章 数据存储 203 10.1 健康助手案例 203 ...

    《Google Android开发入门与实战》.pdf

    7.5 android应用的灵魂——intent和activity介绍与实例 106 7.5.1 实例操作演示 106 7.5.2 实例编程实现 106 7.6 用好列表,做好程序——列表(listview)介绍与实例 111 7.6.1 实例程序演示 111 7.6.2...

    Google.Android开发入门与实战

    7.5 Android应用的灵魂——Intent和Activity介绍与实例 7.5.1 实例操作演示 7.5.2 实例编程实现 7.6 用好列表,做好程序——列表(ListView)介绍与实例 7.6.1 实例程序演示 7.6.2 实例编程实现 7.7 友好地互动交流...

Global site tag (gtag.js) - Google Analytics