先看效果图:

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

/**作为超连接显示的对象*/
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. Oracle与DB2的区别

    系统结构概述 首先,我们需要理解 Oracle 使用的架构,并理解它与 DB2 的不同之处.图 1 展示了 Oracle 的系统结构.将该图与 图 2 进行比较,后者显示了 DB2 的系统结构.在阅读 ...

  2. ASP.NET MVC 之表格分页

    简单效果图:(框架:MVC+NHibernate) 要点: (1)首先建立表格分页Model(GridModel.cs) (2)然后建立数据展示页(PageCloth.cshtml) (3)再建分页版 ...

  3. VS删除未使用的命名空间

    把鼠标光变放在Using+命名空间区域,右键——组织 using->移除未使用的 using

  4. HTML - Textarea - 空格的问题解决方式

    第一种方式: <textarea name="textareaname" rows="XX" cols="XX" ></t ...

  5. SQL中的delete和TRUNCATE的用法

    TRUNCATE TABLE 表名 删除表中的所有行,而不记录单个行删除操作. 语法 TRUNCATE TABLE name 参数 name 是要截断的表的名称或要删除其全部行的表的名称. 注释 TR ...

  6. 关于降低android手机摄像头预览分辨率

    假设现在有这样一个需求需要一直开着手机摄像头 但是不做任何拍照动作 但是每个手机的相机分辨率都不同 而默认预览的时候参数是最大分辨率 这样有时候就回导致电量损耗的加快 所以我们可以采取降低相机分辨率的 ...

  7. iOS nav加角标

    写一个类别加上就可以啦 #import "UIBarButtonItem+Badge.h" #import "BadgeView.h" #import < ...

  8. Xcode的代码片段快捷方式-Code Snippet Library(代码片段库)

    最近换了新电脑,装上Xcode敲代码发现很多以前攒的Code Snippet忘记备份了,总结了一下Code Snippet的设置方法,且行且添加,慢慢积累吧. 如下图:   Title - Code ...

  9. 常用的方法,读取XML节点并赋值给List集合

    一.前言 很多时候也可以直接在XML文件中配置好节点,在程序需要用到的时候,修改XML文件并不需要重新编译,这里是在极光推送中拿出来的一部分代码.代码简单,大家直接看例子吧. 二.实现过程 1.新创建 ...

  10. Linq的查询操作符

    Linq有表达式语法和调用方法的语法.两者是可以结合使用,通常情况下也都是结合使用.表达式语法看上去比较清晰而调用方法的语法实现的功能更多,在此文章中介绍的是表达式语法.方法语法可以看System.L ...