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$%$%[email protected]$dfsfsfsdffds^15959224872)[email protected]&&fefrewafrewfjwio([email protected]()()()[email protected]";
	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$%$%[email protected]$dfsfsfsdffds^15959224872)[email protected]&&fefrewafrewfjwio([email protected]()()()[email protected]";

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>
				
时间: 2024-11-09 18:08:37

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

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

Android UI设计之&lt;十一&gt;自定义ViewGroup,打造通用的关闭键盘小控件ImeObserverLayout

转载请注明出处:http://blog.csdn.net/llew2011/article/details/51598682 我们平时开发中总会遇见一些奇葩的需求,为了实现这些需求我们往往绞尽脑汁有时候还茶不思饭不香的,有点夸张了(*^__^*)--我印象最深的一个需求是在一段文字中对部分词语进行加粗显示.当时费了不少劲,不过还好,这个问题最终解决了,有兴趣的童靴可以看一下:Android UI设计之<六>使用HTML标签,实现在TextView中对部分文字进行加粗显示. 之前产品那边提了这样

从jpanel中调出一个JDialog,并且使得父窗口jpanel的控件不能用

这个问题不好描述,就我的目的吧. 我要一个窗体调出另一个窗体.不过,父窗体只能是jpanel,而不是jframe,这是由我的问题决定的.并且使父窗体不可写. 当然,如果是jframe,这久简单了. 调出可编写的窗口,即子窗口为jdialog,但其构造方法中父窗体只能是jframe或者window, 不过,用这个,就可以使用了: SwingUtilities.getWindowAncestor(this): 不过,jframe模式不知该怎么搞,看哪位大牛能教我. 不过另一方面,虽然成功调出jdia

textView 显示和html的元素控件与进行超链接

1.这些类似html标签可以用Html.fromHtml方法将html标签字符串转化成CharSequence对象,然后再TextView中进行设置: 如: 在.xml文件中 <TextView android:id="@+id/textview1" android:padding="20sp" android:layout_width="wrap_content" android:layout_height="wrap_cont

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

TouchButton 效果图预览 用法 <net.angrycode.library.TouchButton android:id="@+id/touch_btn" android:layout_width="85dp" android:layout_height="85dp" android:layout_centerInParent="true" app:tb_anim_padding="14dp&quo

Android 手机卫士--自定义控件(获取焦点的TextView)

本文地址:http://www.cnblogs.com/wuyudong/p/5906735.html,转载请注明源地址. 本文将实现标题栏下面的textview中的文字跑马灯的效果,就是将一行文字水平循环滚动,效果如下: 实现代码如下: <!-- android:ellipsize="end"添加省略点的所在位置 --> <!-- 想让文字出现跑马灯效果,必须让其获取焦点 --> <!-- android:marqueeRepeatLimit="

用c/c++混合编程方式为ios/android实现一个自绘日期选择控件(一)

本文为原创,如有转载,请注明出处:http://www.cnblogs.com/jackybu 前言 章节: 1.需求描述以及c/c++实现日期和月历的基本操作 2.ios实现自绘日期选择控件 3.android实现自绘日期选择控件 目的: 通过一个相对复杂的自定义自绘控件来分享: 1.ios以及android自定义自绘控件的开发流程 2.objc与c/c++混合编程 3.android ndk的环境配置,android studio ndk的编译模式,swig在android ndk开发中的作

android控件之TextView(显示文本框控件)和EditText(输入文本框控件)

一.TextView(显示文本框控件) 1.TextView控件的常用属性 android:id——控件的id   android:layout_width——控件的宽度  android:layout_height——控件的高度 android:text——文本内容 android:textSize——文本大小 android:textColor——文本颜色 android:background——控件背景 <TextView android:id="@+id/name" an

android 自己定义控件

Android自己定义View实现非常easy 继承View,重写构造函数.onDraw.(onMeasure)等函数. 假设自己定义的View须要有自己定义的属性.须要在values下建立attrs.xml. 在当中定义你的属性. 在使用到自己定义View的xml布局文件里须要增加xmlns:前缀="http://schemas.android.com/apk/res/你的应用所在的包路径". 在使用自己定义属性的时候.使用前缀:属性名,如my:textColor="#FF