我们来看这样一个Text("如何在TextView中插入表情符号如(#f1),邮件[email protected],电话号码18559298168呢,默认的TextView是支持不了这个特性的"),我们如何把里面的表情标签,电话号码等提取出来的,这个我可以用正则表达式可以实现:
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 ArrayListparseStr(String strLink) { if(TextUtils.isEmpty(strLink)){ return null; } ArrayList resultList = new ArrayList (); ArrayList infoList = null; try{ infoList = new ArrayList (); //把所有的email标签都取出来 Matcher matcher = EMAIL_PATTERN.matcher(strLink); 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); } //把所有的phone标签都取出来 Matcher matcher1 = PHONE_PATTERN.matcher(strLink); 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(); LinkInfo info = new LinkInfo(); info.setStartIndex(start); info.setEndIndex(end); info.setContent(matcher2.group()); info.setFace(true); infoList.add(info); } //对infoList进行排序 Collections.sort(infoList); int last = 0; //按照文本的顺序重新组装成一个resultList for(int i=0;i 解析出来后我们就要把这个结果放到view中展示,对于一个自定义view,我们需要重写onMeasure和onDraw,onDraw的流程图如下:
这个View的处理数据源是ArrayList
在onMeasure中,首先我们看如何去measure 表情的宽度
if (info.isFace()) { Bitmap faceBmp = null; if (mFaceType == MSG_FACE_TYPE) { faceBmp = StateFaceModel.getInstance() .getSmallFaceIcon(info.getContent()); } if (faceBmp != null) { int wSize = faceBmp.getWidth() + 4; if (width + wSize >= maxWidth) { width = maxWidth; break forLable; } width += wSize; } continue; }measure 普通文本的宽度:
String text = info.getContent(); if (!TextUtils.isEmpty(text)) { float wSize = tempPaint.measureText(text); if (width + wSize >= maxWidth) { width = maxWidth; break forLable; } width += wSize; }onDraw表情:
LinkInfo info = infoList.get(i); //如果LinkInfo为表情,那么我们需要用canvas.drawBitmap的方式去绘制 if (info.isFace()) { Bitmap faceBmp = null; if (mFaceType == MSG_FACE_TYPE) { faceBmp = StateFaceModel.getInstance() .getSmallFaceIcon(info.getContent()); } if (faceBmp != null) { int xLen = faceBmp.getWidth() + 4; if (curLen + xLen >= displayWidth) { y += fontHeight; curLen = 0; } canvas.drawBitmap(faceBmp, curLen + 2, y - fontHeight + 4, paint); curLen += xLen; } continue; }onDraw中phone,email:
private void paintSelectRectF(Canvas canvas, Paint paint, LinkInfo info) { ArrayListrectList = info.getRectFList(); int len = rectList.size(); for (int i = 0; i < len; i++) { RectF rectF = rectList.get(i); paint.setColor(this.getContext().getResources().getColor(R.drawable.gray3)); canvas.drawRect(rectF.left, rectF.top - 2, rectF.right, rectF.bottom - 2, paint); } } 完成的view的代码是:
public class IntroView extends TextView { private ArrayListtitleList; 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; private OnClickLinkListener Listener; public void setOnClickLinkListener(OnClickLinkListener listener) { this.Listener = listener; } public interface OnClickLinkListener { public abstract void onClick(LinkInfo linkInfo); } 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 titleList) { this.titleList = titleList; displayHeight = 0; requestLayout(); } public void setDisplayWidth(int width) { } public void setSelectedBmp(Bitmap selectedBmp) { this.selectedBmp = selectedBmp; } public void setStarBmp(Bitmap starBmp) { this.starBmp = starBmp; } public void setFaceType(String faceType) { this.mFaceType = faceType; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); try { if (titleList == null || titleList.size() == 0) { return; } curLen = 0; Paint paint = new Paint(); paint.setTextSize(getTextSize()); paint.setAntiAlias(true); paint.setStyle(Style.FILL); float y = -paint.ascent(); y = drawList(canvas, paint, titleList, y); } catch (Exception ex) { } } private float drawList(Canvas canvas, Paint paint, ArrayList infoList, float StartY) { if (infoList == null || infoList.size() == 0) { return StartY; } float y = StartY; float fontHeight = -paint.ascent() + paint.descent(); int len = infoList.size(); int color = getCurrentTextColor(); for (int i = 0; i < len; i++) { LinkInfo info = infoList.get(i); //如果LinkInfo为表情,那么我们需要用canvas.drawBitmap的方式去绘制 if (info.isFace()) { Bitmap faceBmp = null; if (mFaceType == MSG_FACE_TYPE) { faceBmp = StateFaceModel.getInstance() .getSmallFaceIcon(info.getContent()); } if (faceBmp != null) { int xLen = faceBmp.getWidth() + 4; if (curLen + xLen >= displayWidth) { y += fontHeight; curLen = 0; } canvas.drawBitmap(faceBmp, curLen + 2, y - fontHeight + 4, paint); curLen += xLen; } continue; } String strContent = info.getContent(); if (mFaceType == MSG_FACE_TYPE && strContent.startsWith("\n")) { y += fontHeight; curLen = 0; } strContent = strContent.replaceAll("\n", " "); if ((info.isEmail() || info.isPhoneNumber() || info.isWebUrl()) && info.isSelected()) { paintSelectRectF(canvas, paint, info); } float xLen = paint.measureText(strContent); int starLen = 0; if (info.isCommonString()) { paint.setColor(color); } else { paint.setColor(getResources().getColor(R.drawable.blue1)); } //如果只是普通文字,那么只要canvas.drawText就行 if (curLen + xLen + starLen >= displayWidth) { int lenStr = strContent.length(); for (int j = 0; j < lenStr; j++) { float width = paint.measureText(strContent, j, j + 1); if (curLen + width >= displayWidth) { y += fontHeight; curLen = 0; } canvas.drawText(strContent, j, j + 1, curLen, y, paint); curLen += width; } } else { canvas.drawText(strContent, curLen, y, paint); curLen += xLen; } } return y; } private int measureHeight(int measureSpec) { int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); Paint paint = new Paint(); paint.setTextSize(getTextSize()); paint.setAntiAlias(true); paint.setStyle(Style.FILL); displayHeight = -paint.ascent() + paint.descent() + 2;//fontMetrics.bottom - fontMetrics.top + 4; measureList(paint, titleList, 0); if (specMode == MeasureSpec.EXACTLY) { result = specSize; } else { if (specMode == MeasureSpec.AT_MOST) { result = Math.min((int) displayHeight, specSize); } else { result = (int) displayHeight; } } return result; } private float measureList(Paint paint, ArrayList infoList, float StartX) { if (infoList == null || infoList.size() == 0) { displayHeight = StartX; return StartX; } float x = StartX; int len = infoList.size(); float fontHeight = -paint.ascent() + paint.descent(); for (int i = 0; i < len; i++) { LinkInfo info = infoList.get(i); info.getRectFList().clear(); if (info.isFace()) { Bitmap faceBmp = null; if (mFaceType == MSG_FACE_TYPE) { faceBmp = StateFaceModel.getInstance() .getSmallFaceIcon(info.getContent()); } if (faceBmp != null) { int xLen = faceBmp.getWidth() + 4; if (x + xLen >= displayWidth) { displayHeight += fontHeight; x = 0; } x += xLen; } continue; } String strContent = info.getContent(); strContent = strContent.replaceAll("\n", " "); float xLen = paint.measureText(strContent); if (x + xLen >= displayWidth) { float startX = x; int lenStr = strContent.length(); for (int j = 0; j < lenStr; j++) { float width = paint.measureText(strContent, j, j + 1); if (x + width >= displayWidth) { RectF rectF = new RectF(); rectF.set(startX, displayHeight - fontHeight, x, displayHeight); info.addRectF(rectF); displayHeight += fontHeight; x = width; startX = 0; } else { x += width; } } RectF rectF = new RectF(); rectF.set(startX, displayHeight - fontHeight, x - startX, displayHeight); info.addRectF(rectF); } else { RectF rectF = new RectF(); rectF.set(x, displayHeight - fontHeight, x + xLen, displayHeight); info.addRectF(rectF); x += xLen; } } return x; } @Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); if (!this.isEnabled() || Listener == null) { return false; } if (event.getAction() == MotionEvent.ACTION_UP) { float x = event.getX(); float y = event.getY(); boolean flag = cancelCurInfo(x, y); if (flag) { return false; } if (clickLink(titleList, x, y, MotionEvent.ACTION_UP)) { return true; } } else if (event.getAction() == MotionEvent.ACTION_DOWN) { float x = event.getX(); float y = event.getY(); boolean flag = clickLink(titleList, x, y, MotionEvent.ACTION_DOWN); if (flag) { return true; } } else { float x = event.getX(); float y = event.getY(); cancelCurInfo(x, y); } return false; } /** * 如果是phone或是email的链接,那么我们使用canvas.drawRect的方式进行绘制 * @param canvas * @param paint * @param info */ private void paintSelectRectF(Canvas canvas, Paint paint, LinkInfo info) { ArrayList rectList = info.getRectFList(); int len = rectList.size(); for (int i = 0; i < len; i++) { RectF rectF = rectList.get(i); paint.setColor(this.getContext().getResources().getColor(R.drawable.gray3)); canvas.drawRect(rectF.left, rectF.top - 2, rectF.right, rectF.bottom - 2, paint); } } private boolean cancelCurInfo(float x, float y) { if (curInfo == null) { return true; } if (!curInfo.contains(x, y)) { curInfo.setSelected(false); this.invalidate(); curInfo = null; return true; } return false; } private boolean clickLink(ArrayList infoList, float x, float y, int action) { if (infoList == null) { return false; } int len = infoList.size(); for (int i = 0; i < len; i++) { LinkInfo info = infoList.get(i); if (info.isCommonString()) { continue; } if (info.contains(x, y)) { if (action == MotionEvent.ACTION_DOWN) { info.setSelected(true); this.invalidate(); this.curInfo = info; } else if (action == MotionEvent.ACTION_UP) { this.curInfo = null; info.setSelected(false); this.invalidate(); Listener.onClick(info); } return true; } } return false; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); try { int width = measureWidth(widthMeasureSpec); int height = measureHeight(heightMeasureSpec); setMeasuredDimension(width, height); } catch (Exception ex) { ex.printStackTrace(); } } /** * Determines the width of this view * * @param measureSpec A measureSpec packed into an int * @return The width of the view, honoring constraints from measureSpec */ 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 = StateFaceModel.getInstance() .getSmallFaceIcon(info.getContent()); } if (faceBmp != null) { int wSize = faceBmp.getWidth() + 4; if (width + wSize >= maxWidth) { width = maxWidth; break forLable; } width += wSize; } continue; } String text = info.getContent(); 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; } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); } } 代码在:https://github.com/nickgao1986/StepSport