android假设重写onDraw实现一个相似TextView能够显示表情和链接的控件(一)
先看效果图:
写一个超连接支持的对象:
/**作为超连接显示的对象*/
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能够显示表情和链接的控件(一)的更多相关文章
- 一个类似抖音 APP 拍摄按钮效果的控件
TouchButton 一个类似抖音 APP 拍摄按钮效果的控件 效果图预览 用法 <net.angrycode.library.TouchButton android:id="@+i ...
- Android简易实战教程--第四十九话《满屏拖动的控件》
今天做个有意思的效果吧,控件的拖拽,简单实用,逻辑清晰点3分钟看完. 说的很高大上,其实就是拖动Button按钮跟着鼠标位置满手机屏幕跑罢了. 直接上简单的代码吧: public class Main ...
- CListCtrlEx:一个支持文件拖放和实时监视的列表控件——用未公开API函数实现Shell实时监视
一.需求无论何时,当你在Explorer窗口中创建.删除或重命名一个文件夹/文件,或者插入拔除移动存储器时,Windows总是能非常快速地更新它所有的视图.有时候我们的程序中也需要这样的功能,以便当用 ...
- C# Winform下一个热插拔的MIS/MRP/ERP框架(通用控件)
一直对商业控件不感冒, 结合日常工作, 我写了几个常用控件. 一.下拉框控件(仿Access下拉框:F4下拉,自动输入,支持单/多列显示),可在Datagridview中使用. 1.常规: 2.Dat ...
- 解决问题--VS2012中一个Panel覆盖另一个Panel时拖动时容易造成两个控件成父子关系的避免
在*.Designer.cs中,假如想把panel1覆盖到panel2上,但是VS自动让panel1成为panel2的子控件了,在文件中会有this.panel2.Controls.Add(this. ...
- 由一个滑动条的任务需求产生一个对UISlider控件的探讨
任务需求样式:
- 一个小小的即时显示当前时间的jqurey控件
效果: <div class="nowTime"> <span></span>年 <span></span>月 < ...
- 做个简单的Android列表字母索引控件
相信大家在许多App中都见到过带字母索引的界面,比如我最近看到的这个开源控件: WaveSideBar 很酷是不是?!!!如果加在例如联系人列表界面上,大大提升了用户体验. 那么这个索引控件要怎么做呢 ...
- Pro Android 4 第六章 构建用户界面以及使用控件(一)
目前为止,我们已经介绍了android的基础内容,但是还没开始接触用户界面(UI).本章我们将开始探讨用户界面和控件.我们先讨论一下android中UI设计的一般原理,然后我们在介绍一下an ...
随机推荐
- python学习之路-2 初识python数据类型
数字 int(整型) 在32位机器上,整数的位数为32位,取值范围为-2**31-2**31-1,即-2147483648-2147483647 在64位系统上,整数的位数为64位,取值范围为-2** ...
- Kafka在Linux环境下搭建过程
准备工作 Kafka集群是把状态保存在Zookeeper中的,首先要搭建Zookeeper集群.由于我们之前的分布式系统中已经安装zookeeper服务,这里不进行zookeeper安装教程以及应用教 ...
- 应对Deadline,时间怎么安排?
问题定义 项目过程中,每项任务都是有时间要求的,一般体现为"截止时间".即Deadline. 怎样安排时间,才干在Deadline之前完毕任务呢? 有效实践 错误做法 在Deadl ...
- chroot 与 jail
所谓“监牢”就是指通过chroot机制来更改某个进程所能看到的根文件夹,即将某进程限制在指定文件夹中,保证该进程仅仅能对该文件夹及其子文件夹的文件有所动作,从而保证整个server的安全. 创建chr ...
- [转]Laravel 4之控制器
Laravel 4之控制器 http://dingjiannan.com/2013/laravel-controller/ 控制器 通常Laravel控制器文件放在app/controllers/目录 ...
- [HeadFirst-HTMLCSS入门][第九章盒模式]
新属性 line-height 行间距 line-height: 1.6em; border 边框 属性值 solid 实线 double 双实线 groove 一个槽 outset 外凸 inset ...
- [Python][自己写的杀病毒脚本]
电脑里的HTML都插入了一段VB病毒代码..只能自己手动清除了..发现Python确实好用 import os import re; Root = ["H:"]; for root ...
- win7 AnkhSVN 安装报错
重装系统后,需要安装AnkhSVN,结果一直报如下错误 An error occurred during the installation of assembly"Microsoft.VC8 ...
- vs2013 JS代码提示
1.JS提示 在Js文件头部加 /// <reference path="ext-all-dev.js" /> 要求引用的js和本js在同一目录,否则需要全部路径
- 本地计算机上的OracleOraDb11g_home2TNSListener服务启动又停止了。
电脑上装了oracle后启动很慢,然后我就不oracle服务设置成手动启动,没想到今天启动的时候居然报错 折腾了一上午,终于搞定, 在环境变量中把ORACLE_HOME 设置成D:\app\XL\pr ...