首页 > 代码库 > 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 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>
<span style="font-family: Arial, Helvetica, sans-serif;">IntroView的主题思想是在onMeasure里的measureWidth和measureHeight时来获取ArrayList<LinkInfo> titleList每个LinkInfo的位置信息,并获取这个IntroView的高度和宽度,</span>
然后onDraw的时候通过循环来绘制titleList的每个LinkInfo
<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>