先看效果图:

写一个超连接支持的对象:

/**作为超连接显示的对象*/
public class LinkInfo implements Comparable<LinkInfo>{
private String content;
private String type;
private String id;
private boolean bIsFace = false;
private boolean bSelected = false;
public static final String EMAIL = "Email";
public static final String WEBURL = "WebUrl";
public static final String PHONENUMBER = "PhoneNumber";
private int startIndex;
private int endIndex;
}

对于下面的字符串做这种解析:

		String s = "(#大笑)%$%$%3434343434343$%$%youjiancau@163.com$dfsfsfsdffds^15959224872)dfsfdsafsaf@153.cn&&fefrewafrewfjwio(fsfsfsd@tre.com.cn()()()www.baidu.com3242343243www.sohu.com@afjiofjfjaof";
	private static Pattern EMAIL_PATTERN = Patterns.EMAIL_ADDRESS;
private static Pattern PHONE_PATTERN = Patterns.PHONE;
private static Pattern WEBURL_PATTERN = Patterns.WEB_URL;
public static ArrayList<LinkInfo> parseStr(String strLink) {
if(TextUtils.isEmpty(strLink)){
return null;
}
ArrayList<LinkInfo> resultList = new ArrayList<LinkInfo>();
ArrayList<LinkInfo> infoList = null;
try{
infoList = new ArrayList<LinkInfo>();
<span style="white-space:pre"> </span><strong> Matcher matcher = EMAIL_PATTERN.matcher(strLink); //寻找字符串里的email的位置</strong>
int begin = 0;
while(matcher.find()) {
int start = matcher.start();
int end = matcher.end();
LinkInfo info = new LinkInfo();
info.setStartIndex(start);
info.setEndIndex(end);
info.setContent(matcher.group());
info.setType(LinkInfo.EMAIL);
infoList.add(info);
} <strong>Matcher matcher1 = PHONE_PATTERN.matcher(strLink);//寻找字符串里的号码的位置</strong>
while(matcher1.find()) {
int start = matcher1.start();
int end = matcher1.end();
LinkInfo info = new LinkInfo();
info.setStartIndex(start);
info.setEndIndex(end);
info.setContent(matcher1.group());
info.setType(LinkInfo.PHONENUMBER);
infoList.add(info);
} //(#大笑)
Pattern pattern = Pattern.compile("(\\(#\\S{1,2}\\))");
Matcher matcher2 = pattern.matcher(strLink);
while(matcher2.find()) {
int start = matcher2.start();
int end = matcher2.end();
System.out.println("====start="+start+"end="+end+"match group="+matcher2.group());
LinkInfo info = new LinkInfo();
info.setStartIndex(start);
info.setEndIndex(end);
info.setContent(matcher2.group());
info.setFace(true);
infoList.add(info);
} Collections.sort(infoList);
int last = 0;
for(int i=0;i<infoList.size();i++) {
LinkInfo info = infoList.get(i);
if(begin != info.getStartIndex()){
LinkInfo infoBefore = new LinkInfo();
infoBefore.setContent(strLink.substring(begin,info.getStartIndex()));
resultList.add(infoBefore);
}
resultList.add(info);
begin = info.getEndIndex();
last = info.getEndIndex();
}
if(last < strLink.length()) {
LinkInfo info = new LinkInfo();
info.setContent(strLink.substring(last,strLink.length()));
resultList.add(info);
} }catch(Exception ex){
ex.printStackTrace();
}
return resultList;
}

activity的Layout:

<?

xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/white" > <include
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:id="@+id/header"
layout="@layout/news_header" /> <RelativeLayout
android:id="@+id/title"
android:layout_above="@id/header"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:background="@drawable/white"
android:gravity="center_horizontal" > <com.kaixin001.view.IntroView
android:id="@+id/news_item_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_marginTop="20dp"
android:enabled="true"
android:textColor="@drawable/black"
android:textSize="16sp"
android:textStyle="bold" />
</RelativeLayout> </RelativeLayout>
IntroView有这样一个方法来载入字符串:
<pre name="code" class="java">public class IntroView extends TextView {

	private ArrayList<LinkInfo> titleList;
private int displayWidth = 0;
private float displayHeight = 0;
private float curLen = 0;
private Bitmap starBmp;
private Bitmap selectedBmp;
private float posX = 0;
private float posY = 0;
private LinkInfo curInfo;//当前点击的Link对象
private OnClickLinkListener Listener; private String mFaceType = MSG_FACE_TYPE;
public static final String MSG_FACE_TYPE = "msgtype";
public static final String STATUS_FACE_TYPE = "statustype"; public IntroView(Context context) {
super(context);
} public IntroView(Context context, AttributeSet attrs) {
super(context, attrs);
} public IntroView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
} public void setTitleList(ArrayList<LinkInfo> titleList){
this.titleList = titleList;
displayHeight = 0;
requestLayout();
}
}<span style="font-family: Arial, Helvetica, sans-serif;">  </span>
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-family:Arial, Helvetica, sans-serif;">activity里这样来调用:</span>
<span style="font-family:Arial, Helvetica, sans-serif;"></span>

IntroView news_item_text = (IntroView)findViewById(R.id.news_item_text);

//不支持字符串里有\n

String s = "(#大笑)%$%$%3434343434343$%$%youjiancau@163.com$dfsfsfsdffds^15959224872)dfsfdsafsaf@153.cn&&fefrewafrewfjwio(fsfsfsd@tre.com.cn()()()www.baidu.com3242343243www.sohu.com@afjiofjfjaof";

news_item_text.setTitleList(ParseNewsInfoUtil.parseStr(s));

news_item_text.setOnClickLinkListener(this);

<span style="font-family:Arial, Helvetica, sans-serif;">
</span>
</pre><pre code_snippet_id="447070" snippet_file_name="blog_20140810_12_4943450" name="code" class="java"><span style="font-family: Arial, Helvetica, sans-serif;">IntroView的主题思想是在onMeasure里的measureWidth和measureHeight时来获取ArrayList<LinkInfo> titleList每一个LinkInfo的位置信息。并获取这个IntroView的高度和宽度,</span>
然后onDraw的时候通过循环来绘制titleList的每一个LinkInfo
</pre><pre code_snippet_id="447070" snippet_file_name="blog_20140810_15_8956611" name="code" class="java"><strong><span style="white-space:pre">	</span>@Override
<span style="white-space:pre"> </span>protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
<span style="white-space:pre"> </span>super.onMeasure(widthMeasureSpec, heightMeasureSpec);
<span style="white-space:pre"> </span>try{
<span style="white-space:pre"> </span>int width = measureWidth(widthMeasureSpec);
<span style="white-space:pre"> </span>int height = measureHeight(heightMeasureSpec);
<span style="white-space:pre"> </span>setMeasuredDimension(width, height);
<span style="white-space:pre"> </span>}catch(Exception ex){
<span style="white-space:pre"> </span>ex.printStackTrace();
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}</strong>
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-family: Arial, Helvetica, sans-serif;"> <span style="white-space:pre">			</span></span><pre name="code" class="java"> private int measureWidth(int measureSpec) {
int result = 0; int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
int initialWidth = getPaddingLeft() + getPaddingRight();
int width = initialWidth;
int maxWidth = 0; TextPaint tempPaint = null; if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
if (tempPaint == null) {
tempPaint = new TextPaint();
tempPaint.setStyle(Style.FILL);
tempPaint.setAntiAlias(true);
tempPaint.setTextSize(getTextSize());
} if (titleList != null && titleList.size() > 0) {
maxWidth = specSize; int size = titleList.size();
forLable:
for (int i = 0; i < size; i++) {
LinkInfo info = titleList.get(i); if (info.isFace()) {
Bitmap faceBmp = null;
if(mFaceType == MSG_FACE_TYPE) {
faceBmp = MessageFaceModel.getInstance().getFaceIcon(info.getContent());
}
if (faceBmp != null) {
int wSize = faceBmp.getWidth() + 4;
<strong> if (width + wSize >= maxWidth)</strong> { //这里表示已经计算的宽度大于控件的宽度,那就返回maxWidth就能够了
width = maxWidth;
break forLable;
}
width += wSize;
}
continue;
} String text = info.getContent();
text = text.replaceAll("\n", " "); //由于该控件不支持\n,所以把这个换成空格
if (!TextUtils.isEmpty(text)) {
float wSize = tempPaint.measureText(text);
if (width + wSize >= maxWidth) {
width = maxWidth;
break forLable;
}
width += wSize;
} }
} result = width;
} displayWidth = result;
return result;
}

<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-family: Arial, Helvetica, sans-serif;">                                                                                </span>

android假设重写onDraw实现一个相似TextView能够显示表情和链接的控件(一)的更多相关文章

  1. 一个类似抖音 APP 拍摄按钮效果的控件

    TouchButton 一个类似抖音 APP 拍摄按钮效果的控件 效果图预览 用法 <net.angrycode.library.TouchButton android:id="@+i ...

  2. Android简易实战教程--第四十九话《满屏拖动的控件》

    今天做个有意思的效果吧,控件的拖拽,简单实用,逻辑清晰点3分钟看完. 说的很高大上,其实就是拖动Button按钮跟着鼠标位置满手机屏幕跑罢了. 直接上简单的代码吧: public class Main ...

  3. CListCtrlEx:一个支持文件拖放和实时监视的列表控件——用未公开API函数实现Shell实时监视

    一.需求无论何时,当你在Explorer窗口中创建.删除或重命名一个文件夹/文件,或者插入拔除移动存储器时,Windows总是能非常快速地更新它所有的视图.有时候我们的程序中也需要这样的功能,以便当用 ...

  4. C# Winform下一个热插拔的MIS/MRP/ERP框架(通用控件)

    一直对商业控件不感冒, 结合日常工作, 我写了几个常用控件. 一.下拉框控件(仿Access下拉框:F4下拉,自动输入,支持单/多列显示),可在Datagridview中使用. 1.常规: 2.Dat ...

  5. 解决问题--VS2012中一个Panel覆盖另一个Panel时拖动时容易造成两个控件成父子关系的避免

    在*.Designer.cs中,假如想把panel1覆盖到panel2上,但是VS自动让panel1成为panel2的子控件了,在文件中会有this.panel2.Controls.Add(this. ...

  6. 由一个滑动条的任务需求产生一个对UISlider控件的探讨

    任务需求样式:

  7. 一个小小的即时显示当前时间的jqurey控件

    效果: <div class="nowTime"> <span></span>年 <span></span>月 < ...

  8. 做个简单的Android列表字母索引控件

    相信大家在许多App中都见到过带字母索引的界面,比如我最近看到的这个开源控件: WaveSideBar 很酷是不是?!!!如果加在例如联系人列表界面上,大大提升了用户体验. 那么这个索引控件要怎么做呢 ...

  9. Pro Android 4 第六章 构建用户界面以及使用控件(一)

         目前为止,我们已经介绍了android的基础内容,但是还没开始接触用户界面(UI).本章我们将开始探讨用户界面和控件.我们先讨论一下android中UI设计的一般原理,然后我们在介绍一下an ...

随机推荐

  1. How to check for and disable Java in OS X

    Java used to be deeply embedded in OS X, but in recent versions of the OS it's an optional install. ...

  2. [Git] --no-verify

    Somtimes, the project might set the commit message guide line, if your commit doesn't meet the requi ...

  3. phonegap环境配置与基本操作

    一.开发环境配置: 1.工具环境安装: 安装java sdk 1.6以上版本号,Android Development Tools.ant,系统变量 Path后面加入 新增名稱 JAVA_HOME 值 ...

  4. 不同浏览器对URL最大长度的限制(转)

    1.今天碰到一个bug,window.open后面的页面,接收参数不全,导致后台报错.实验了一下.发现是使用get方法请求服务器时,URL过长所致 微软官方的说明: http://support.mi ...

  5. Code Complete阅读笔记(二)

    2015-03-06   328   Unusual Data Types    ——You can carry this technique to extremes,putting all the ...

  6. Android5.0+(CollapsingToolbarLayout)

    CollapsingToolbarLayout作用是提供了一个可以折叠的Toolbar,它继承至FrameLayout,给它设置layout_scrollFlags,它可以控制包含在Collapsin ...

  7. iOS开发 ~应用程序设计理念:视图控制器(UIViewController)、视图(UIView)

    应用程序设计理念:视图控制器(UIViewController).视图(UIView) 利用视图控制器(底层)管理视图(外观),一对一 1.视图的作用:负责显示的外观 2.视图控制器的作用:创建界面. ...

  8. 6、Khala的登录生命周期管理

    khala能够对设备进行生命周期管理,并提供了与生命周期相关的接口,用户只需在具体的设备类型实现类中重写这些生命周期接口,即可享受khala对于生命周期管理的同时定制与业务相关的操作.具体接口解释如下 ...

  9. 求一无序数组中第n大的数字 - 快速选择算法

    逛别人博客的时候,偶然看到这一算法题,顺便用C++实现了一下. 最朴素的解法就是先对数组进行排序,返回第n个数即可.. 下面代码中用的是快速选择算法(不晓得这名字对不对) #include <v ...

  10. (转)android ndk 给结构体赋值的方法

    转自:http://www.cnweblog.com/fly2700/archive/2012/03/21/320083.html 1,java 代码 结构体定义 public class Media ...